我有两个如下所示的数据框
t1 = pd.DataFrame({'person_id':[1,2,3],'observation_date':[np.nan,np.nan,np.nan],'observation_datetime':[np.nan,np.nan,np.nan]})
t2 = pd.DataFrame({'person_id':[1,2,3],'value_as_string':['5/28/2007','5/30/2007','6/4/2007']}).set_index('person_id')['value_as_string']
它们看起来如下图
这就是我试图获得输出的结果
t1['observation_date'] = t1['person_id'].map(t2)
t1['observation_date'] = pd.to_datetime(t1['observation_date'])
t1['observation_datetime'] = pd.to_datetime(t1['observation_date']).dt.strftime('%m/%d/%Y %H:%M:%S')
尽管可以正常工作,但在真实数据中却要花费大量时间
请注意,我正在尝试对大小为 100万个记录的t1
个数据帧和大小为 15k 个记录的t2
个数据帧进行此操作。因此,任何有效的方法都会有所帮助
我希望我的输出数据帧如下图所示
答案 0 :(得分:2)
ids = list(range(1, 15000))
dte = ['5/28/2007','5/30/2007','6/4/2007'] * 5000
t1 = pd.DataFrame({'person_id': ids})
t2 = pd.DataFrame({'person_id': ids,
'value_as_string': dte)
合并方法
x = t1.merge(t2, how='left', on='person_id', how='left')
# 5.19 ms ± 408 µs per loop
加入方法
x = t1.set_index('person_id').join(df2.set_index('person_id'), how='left')
# 3.02 ms ± 91.4 µs per loop
使用字典的映射方法
t1['observation_date'] = t1['person_id'].map(
t2.set_index('person_id')['value_as_string'].to_dict())
# 2.73 ms ± 240 µs per loop
没有字典的地图方法
t1['observation_date'] = t1['person_id'].map(t2.set_index('person_id')['value_as_string'])
# 2.33 ms ± 260 µs per loop
所以
t1['observation_date'] = pd.to_datetime(
t1['person_id'].map(t2.set_index('person_id')['value_as_string']))
t1['observation_datetime'] = t1['observation_date'].dt.strftime('%m/%d/%Y %H:%M:%S')
答案 1 :(得分:1)
对于您的问题,我有一种解决方法。为什么不使用映射,而不是使用大熊猫中的合并等更快的方法?我已经使用了将近一百万的记录,而且速度惊人。
合并过程始于两个数据框。尝试做
df = t1.merge(t2, on = 'person_id', how='inner')
这将对两个数据帧(t1和t2)中两列的person_id进行内部联接。您将在结果数据框中引入一个新列。然后,您可以使用简单的列操作将值填充到目标列中。
希望有帮助。
答案 2 :(得分:1)
转换为日期时间格式也要花费大量时间,您可以通过显式指定日期时间格式作为pd.to_datetime
的参数来加快转换速度。对于您的情况,它最多可以提高10倍。
模拟您的情况。
import pandas as pd
t1 = pd.DataFrame({'person_id':[i for i in range(1000000)],'observation_date':[np.nan]*1000000,'observation_datetime':[np.nan]*1000000})
t2 = pd.DataFrame({'person_id':np.random.choice(1000000, replace=False, size=15000),
'value_as_string':['5/28/2007','5/30/2007','6/4/2007']*5000}).set_index('person_id')['value_as_string']
def map_infere_datetime_format(t1, t2):
t1['observation_date'] = t1['person_id'].map(t2)
t1['observation_date'] = pd.to_datetime(t1['observation_date'])
t1['observation_datetime'] = pd.to_datetime(t1['observation_date']).dt.strftime('%m/%d/%Y %H:%M:%S')
return t1
# explicitly specify format instead of pandas doing the work for you
def map_explicit_datetime_format(t1, t2):
t1['observation_date'] = t1['person_id'].map(t2)
t1['observation_date'] = pd.to_datetime(t1['observation_date'], format='%m/%d/%Y')
t1['observation_datetime'] = t1['observation_date'].dt.strftime('%m/%d/%Y %H:%M:%S')
return t1
在Google colab上运行的测试结果:
%%timeit -n3
map_infere_datetime_format(t1, t2)
# 3 loops, best of 3: 2.04 s per loop
%%timeit -n3
map_explicit_datetime_format(t1, t2)
# 3 loops, best of 3: 290 ms per loop
由于t2较小,因此在进行映射之前将t2转换为日期时间是有意义的。
希望有帮助!