[英]Modifying the date index of pandas dataframe
我正在嘗試編寫一個高效的函數,該函數將采用平均大小的數據框(~5000 行)並返回一個包含最新年份(和相同索引)列的數據框,以便對於原始數據框的每個日期索引包含該月份日期介於某個預先指定的開始日期 (st_d) 和結束日期 (end_d) 之間。 我寫了一個代碼,其中年份遞減,直到特定日期索引的月份在所需范圍內。 然而,它真的很慢。 對於只有 366 個條目的數據幀,它需要大約 0.2 秒。 我需要使它至少快一個數量級,以便我可以將它重復應用於數以萬計的數據幀。 我將非常感謝您對此提出的任何建議。
import pandas as pd
import numpy as np
import time
from pandas.tseries.offsets import MonthEnd
def year_replace(st_d, end_d, x):
tmp = time.perf_counter()
def prior_year(d):
# 100 is number of the years back, more than enough.
for i_t in range(100):
#The month should have been fully seen in one of the data years.
t_start = pd.to_datetime(str(d.month) + '/' + str(end_d.year - i_t), format="%m/%Y")
t_end = t_start + MonthEnd(1)
if t_start <= end_d and t_start >= st_d and t_end <= end_d and t_end >= st_d:
break
if i_t < 99:
return t_start.year
else:
raise BadDataException("Not enough data for Gradient Boosted tree.")
output = pd.Series(index = x.index, data = x.index.map(lambda tt: prior_year(tt)), name = 'year')
print("time for single dataframe replacement = ", time.perf_counter() - tmp)
return output
i = pd.date_range('01-01-2019', '01-01-2020')
x = pd.DataFrame(index = i, data=np.full(len(i), 0))
st_d = pd.to_datetime('01/2016', format="%m/%Y")
end_d = pd.to_datetime('01/2018', format="%m/%Y")
year_replace(st_d, end_d, x)
我的建議是:盡可能避免循環並檢查是否有更簡單的方法可用。
如果我明白你的目標是:
對於給定的
start
和stop
時間戳,找到最新的(更高的)時間戳t
,其中月份是從索引給出的,並且start <= t <= stop
我相信這可以形式化如下(為了方便起見,我保留了您的函數簽名):
def f(start, stop, x):
assert start < stop
tmp = time.perf_counter()
def y(d):
# Check current year:
if start <= d.replace(day=1, year=stop.year) <= stop:
return stop.year
# Check previous year:
if start <= d.replace(day=1, year=stop.year-1) <= stop:
return stop.year-1
# Otherwise fail:
raise TypeError("Ooops")
# Apply to index:
df = pd.Series(index=x.index, data=x.index.map(lambda t: y(t)), name='year')
print("Tick: ", time.perf_counter() - tmp)
return df
它似乎按要求執行得更快(將近二十年,我們應該確定基准,例如:使用timeit
):
Tick: 0.004744200000004639
無需迭代,您只需檢查當前和上一年即可。 如果失敗,則不能存在滿足您要求的時間戳。
如果必須保留日期,則只需刪除replace
方法中的day=1
。 如果您要求切割標准不相等,則相應地修改不等式。 以下功能:
def y(d):
if start < d.replace(year=stop.year) < stop:
return stop.year
if start < d.replace(year=stop.year-1) < stop:
return stop.year-1
raise TypeError("Ooops")
返回與您相同的數據幀。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.