【发布时间】:2018-03-26 22:57:35
【问题描述】:
我目前有一个数据框,其中包含 ID、类别和由开始日期和结束日期给出的时间跨度。我想将此时间跨度数据框转换为一个,其中每一行对应于每个 ID 和类别的给定 YYYY MM。
下面的代码显示了一个开始 df 的示例,以及我通常会做什么来创建这个 YYYY MM 枚举数据框。日期有一些烦人的数学运算,以确保我捕获开始日期和结束日期之间的每个 YYYY MM 包括在内,但这对我的问题来说并不是非常重要。
我遇到的问题是,实际上,我需要在具有近 600 万个时间跨度条目的 df 上运行它。我想知道是否有更好的方法来利用熊猫而不是基本上用 for 循环来完成这个?这将运行,但最终需要几个小时才能爬过整个数据框。对我来说,我似乎不太明显可以使用循环以外的任何方法来完成此操作?
import pandas as pd
from dateutil.relativedelta import relativedelta
from datetime import timedelta
df = pd.DataFrame({'ID': [1,1,2], 'start': ['2001-01-01', '2002-01-02', '2001-05-07'],
'end': ['2002-01-12', '2002-01-14', '2002-05-01'], 'category': ['A', 'B', 'A']})
df['start'] = pd.to_datetime(df['start'])
df['end'] = pd.to_datetime(df['end'])
df_list = []
for index,row in df.iterrows():
start = row.start - timedelta(days=row.start.day-1)
stop = row.end - timedelta(days=row.end.day-1) + relativedelta(months=1)
tempdf = pd.DataFrame({'ID': row.ID, 'year':pd.date_range(start, stop, freq='1M').year,
'month': pd.date_range(start, stop, freq='1M').month,
'category': row.category})
df_list.append(tempdf)
newdf = pd.concat(df_list, ignore_index=True)
【问题讨论】:
-
如果 3 行扩展到 27 行(增加 9 倍),那么平均 6M 将增加到 162M 行,我怀疑您是否可以将其全部放入内存。
-
内存应该不是问题,因为我可以将大部分字段存储为小整数。由于我已经清理了 span df 以确保给定 ID-category 组合的时间跨度不会重叠,我总是可以只处理较小的文件块。但这对速度没有帮助......
-
为了提供更多上下文,我有第三个数据框,ID YYYY 和 MM 作为列。我想向该数据框添加一个类别列。由于合并条件是针对一个 df 的 YYYY MM 在另一个时间跨度内,所以并不那么简单。编码的查找太慢了,所以我认为这个 YYYY MM 解析的数据帧应该允许我使用 DataFrame.merge(on=['ID', 'year', 'month']) 更快地完成这个任务
-
最终它需要大约 40 GB 的内存才能完成,这并不可怕。通过将循环外的开始和停止计算为矢量化表达式,我能够大大加快它的速度,但它仍然需要大约 3-4 小时才能运行。我想这是不可避免的,因为我基本上是在创建一个全新的数据框:(