将日期从一个数据帧映射到另一个大数据帧的优雅而高效的方法

2024-04-23 19:15:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个数据帧如下所示

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']

它们如下所示

enter image description here

这就是我试图得到的结果

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数据帧执行此操作。所以任何有效的方法都是有用的

我希望我的输出数据帧如下所示

enter image description here


Tags: 数据iddataframedatetimedatestringvalueas
3条回答

转换为datetime格式也需要很多时间,可以通过显式指定datetime格式作为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转换为datetime是有意义的,这样可以获得较小的加速。你知道吗

希望有帮助!你知道吗

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

dict地图法

t1['observation_date'] = t1['person_id'].map(
       t2.set_index('person_id')['value_as_string'].to_dict())
# 2.73 ms ± 240 µs per loop

无dict的Map方法

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')

我有办法解决你的问题。为什么不使用一种更快的方法来代替映射,比如在pandas中使用merge?我在近一百万张唱片上用过它,速度惊人。你知道吗

合并过程从两个数据帧开始。试着做

df =  t1.merge(t2, on = 'person_id', how='inner')

这将在两个数据帧(t1和t2)的两个列上对person\ id进行内部联接。您将在结果数据帧中引入一个新列。然后可以使用简单的列操作来填充目标列中的值。你知道吗

希望有帮助。你知道吗

相关问题 更多 >