我有2个pandas
个数据框,其中一个包含测量日期,另一个包含带有事件ID的日期。
DF1
from datetime import datetime as dt
from datetime import timedelta
import pandas as pd
import numpy as np
today = dt.now()
ndays = 10
df1 = pd.DataFrame({'Date': [today + timedelta(days = x) for x in range(ndays)], 'measurement': pd.Series(np.random.randint(1, high = 10, size = ndays))})
df1.Date = df1.Date.dt.date
Date measurement
2018-01-10 8
2018-01-11 2
2018-01-12 7
2018-01-13 3
2018-01-14 1
2018-01-15 1
2018-01-16 6
2018-01-17 9
2018-01-18 8
2018-01-19 4
DF2
df2 = pd.DataFrame({'Date': ['2018-01-11', '2018-01-14', '2018-01-16', '2018-01-19'], 'letter': ['event_a', 'event_b', 'event_c', 'event_d']})
df2.Date = pd.to_datetime(df2.Date, format = '%Y-%m-%d')
df2.Date = df2.Date.dt.date
Date event_id
2018-01-11 event_a
2018-01-14 event_b
2018-01-16 event_c
2018-01-19 event_d
我在df1
event_id
df2
中提供日期,只有在两个事件日期之间。结果数据框看起来像:
DF3
today = dt.now()
ndays = 10
df3 = pd.DataFrame({'Date': [today + timedelta(days = x) for x in range(ndays)], 'measurement': pd.Series(np.random.randint(1, high = 10, size = ndays)), 'event_id': ['event_a', 'event_a', 'event_b', 'event_b', 'event_b', 'event_c', 'event_c', 'event_d', 'event_d', 'event_d']})
df3.Date = df3.Date.dt.date
Date event_id measurement
2018-01-10 event_a 4
2018-01-11 event_a 2
2018-01-12 event_b 1
2018-01-13 event_b 5
2018-01-14 event_b 5
2018-01-15 event_c 4
2018-01-16 event_c 6
2018-01-17 event_d 6
2018-01-18 event_d 9
2018-01-19 event_d 6
我用来实现这个目的的代码是:
n = 1
while n <= len(list(df2.Date)) - 1 :
for date in list(df1.Date):
if date <= df2.iloc[n].Date and (date > df2.iloc[n-1].Date):
df1.loc[df1.Date == date, 'event_id'] = df2.iloc[n].event_id
n += 1
我正在使用的数据集远远大于此(几百万行),并且此方法运行时间太长。有没有更有效的方法来实现这一目标?
答案 0 :(得分:0)
因此,提高性能有很多方面。 我的第一个问题是:它必须是一个大熊猫框架开始吗?意思是df1和df2只是元组列表或列表列表?
事情是,在访问项目时,pandas会增加很多开销,尤其是在单独设置值时。 Pandas在矢量化操作方面表现出色,但我现在还没有看到有效的替代方案(也许有人想出这样的答案,这将是理想的)。
现在我要做的是:
d1 = df1.to_records()
你得到的是一组元组,基本上与数据帧具有相同的结构。现在运行您的算法,但不是对pandas数据帧进行操作,而是对元组d1
和d2
使用第三个元组列表d3
存储新创建的数据(每个元组是一行)
现在,如果您愿意,可以将d3转换回pandas数据帧:
df3 = pd.DataFrame.from_records(d3, myKwArgs**)
这将显着加快您的代码速度,我假设超过100-1000%。它确实增加了内存使用量,所以如果内存不足,请尽量避免将pandas数据帧全部放在一起,或者在使用它们创建记录时取消引用未使用的pandas帧df1, df2
(如果遇到问题,请调用gc手动地)。
编辑:这是使用上述程序的代码版本:
d3 = []
n = 1
while n < range(len(d2)):
for i in range(len(d1)):
date = d1[i][0]
if date <= d2[n][0] and date > d2[n-1][0]:
d3.append( (date, d2[n][1], d1[i][1]) )
n += 1
答案 1 :(得分:0)
您可以尝试使用df.apply()方法来实现此目的。请参阅pandas.DataFrame.apply。我认为我的代码比你的代码更快。
我的方法:
df3 = pd.merge(df1, df2, on='Date', how='outer')
df3['Date'] = pd.to_datetime(df3.Date)
df3.sort_values(by='Date')
new_event_id = np.nan
def set_event_date(df3):
global new_event_id
if df3.event_id is not np.nan:
new_event_id = df3.event_id
return new_event_id
df3['new_event_id'] = df3.apply(set_event_date,axis=1)
最终输出将是:
Date Measurement New_event_id
0 2018-01-11 2 event_a
1 2018-01-12 1 event_a
2 2018-01-13 3 event_a
3 2018-01-14 6 event_b
4 2018-01-15 3 event_b
5 2018-01-16 5 event_c
6 2018-01-17 7 event_c
7 2018-01-18 9 event_c
8 2018-01-19 7 event_d
9 2018-01-20 4 event_d
让我知道一旦你尝试了我的解决方案,它的工作速度比你的快。 感谢。