熊猫在合适的时间添加价值

时间:2017-01-15 10:18:55

标签: python pandas dataframe merge

我有两个由Date索引的DataFrame,在一个DataFrame上,每行每小时更改一次,它会更改(有时它会每5分钟更改一次,但有时会有不同的步骤)。

>>> print df2['value']
date
2015-10-06 09:00:00    0.612303
2015-10-06 10:00:00    0.482605
2015-10-06 11:00:00    0.604132

>>> print df1['value']
date
2015-10-06 09:05:00    0.412303
2015-10-06 09:08:00    0.112303
2015-10-06 09:28:00    0.012303
2015-10-06 10:15:00    0.000005
2015-10-06 11:00:00    0.133132

我希望小时h和h + 1之间的df1值具有相应的df2值。

通缉结果:

>>> print df1['value']
date
2015-10-06 09:05:00    0.612303
2015-10-06 09:08:00    0.612303
2015-10-06 09:28:00    0.612303
2015-10-06 10:15:00    0.482605
2015-10-06 11:00:00    0.604132

我怎样才能做到这一点?

3 个答案:

答案 0 :(得分:4)

您可以使用merge_asof为您的示例生成一个正确的值列,其中包含DatetimeIndex:

pd.merge_asof(df1.reset_index(), # see note about reset_index below
              df2.reset_index(),
              on='date', 
              tolerance=pd.Timedelta('1H'))

容差参数允许您指定合并应在有效的特定时间之后多长时间。例如,如果我们指定tolerance=pd.Timedelta('10m')(10分钟),则不是所有值都可以合并,而是某些位置标记为NaN

请注意,我必须在合并之前重置两个帧的索引。我想使用left_index=Trueright_index=True进行合并,但是当传入容差参数时,pandas拒绝允许此操作(这可能是一个错误 - 使用merge_asof如果更改则应该更加整洁)。

答案 1 :(得分:1)

对于Pandas版本0.19.0或更高版本,请参阅ajcr's answer

对于Pandas版本< 0.19.0:您可以将两个DataFrame与concat合并,使用ffill使用所需的值向前填充NaN值,然后update df1值:

import pandas as pd
df2 = pd.DataFrame({'value':[0.612303,0.482605,0.604132]}, index=pd.DatetimeIndex(['2015-10-06 09:00:00', '2015-10-06 10:00:00', '2015-10-06 11:00:00']))
df1 = pd.DataFrame({'value':[0.412303, 0.112303, 0.012303, 0.000005, 0.133132]}, index=pd.DatetimeIndex(['2015-10-06 09:05:00', '2015-10-06 09:08:00', '2015-10-06 09:28:00', '2015-10-06 10:15:00', '2015-10-06 11:00:00']))

df1.update(pd.concat([df1, df2], axis=1).ffill().iloc[:, 1])
print(df1)

产量

                        value
2015-10-06 09:05:00  0.612303
2015-10-06 09:08:00  0.612303
2015-10-06 09:28:00  0.612303
2015-10-06 10:15:00  0.482605
2015-10-06 11:00:00  0.604132

或者,您可以使用searchsorted查找指示df1.index适合df2.index的位置的索引值:

import pandas as pd
df2 = pd.DataFrame({'value':[0.612303,0.482605,0.604132]}, index=pd.DatetimeIndex(['2015-10-06 09:00:00', '2015-10-06 10:00:00', '2015-10-06 11:00:00']))
df1 = pd.DataFrame({'value':[0.412303, 0.112303, 0.012303, 0.000005, 0.133132]}, index=pd.DatetimeIndex(['2015-10-06 09:05:00', '2015-10-06 09:08:00', '2015-10-06 09:28:00', '2015-10-06 10:15:00', '2015-10-06 11:00:00']))

df1['value'] = df2.iloc[df2.index.searchsorted(df1.index, side='right')-1].values
print(df1)

产量

                        value
2015-10-06 09:05:00  0.612303
2015-10-06 09:08:00  0.612303
2015-10-06 09:28:00  0.612303
2015-10-06 10:15:00  0.482605
2015-10-06 11:00:00  0.604132

请注意,searchsorted假定df2.index已按排序顺序排列。如果不是,请先使用df2 = df2.sort_index()

相反,pd.concat返回DatatimeIndex已排序的DataFrame 订单,即使df1.index和/或df2.index未按排序顺序排列。因此,对于第一种方法,不需要调用sort_index

在这两种方法中,searchsorted更快。例如,使用此设置:

import numpy as np
import pandas as pd
N = 1000
df1 = pd.DataFrame(np.random.random(N), index=pd.date_range('2000-1-1', periods=N, freq='14T'))
df2 = pd.DataFrame(np.random.random(int(N/60*14)), index=pd.date_range('2000-1-1', periods=int(N/60*14), freq='1H'))
df3, df4 = df1.copy(), df1.copy()

df3.update(pd.concat([df3, df2], axis=1).ffill().iloc[:, 1])
df4[0] = df2.iloc[df2.index.searchsorted(df4.index, side='right')-1].values
assert df3.equals(df4)

searchsorted快了〜2.8倍:

In [88]: %timeit df3.update(pd.concat([df3, df2], axis=1).ffill().iloc[:, 1])
100 loops, best of 3: 2.13 ms per loop

In [89]: %timeit df4[0] = df2.iloc[df2.index.searchsorted(df4.index, side='right')-1].values
1000 loops, best of 3: 744 µs per loop

In [90]: len(df1), len(df2)
Out[90]: (1000, 233)

答案 2 :(得分:0)

在你的df1中创建一个新列"每小时"从它的索引 然后在这个新创建的列上简单地将df1与df2连接,以添加df2中的值。

将尽快发布代码:)

编辑:正如所承诺的,这是代码

import pandas as pd
from datetime import datetime

df1 = pd.read_csv("df1.csv",index_col="date", parse_dates=True)
df2 = pd.read_csv("df2.csv",index_col="date", parse_dates=True)


def fromTimeStampToHour(date):
    datetimeObj = date.to_datetime()
    hourlyObj = datetime(year=datetimeObj.year,month= datetimeObj.month, day = datetimeObj.day, hour=datetimeObj.hour)
    return hourlyObj

df1["Hours"] = df1.index.map(lambda x: fromTimeStampToHour(x))

print pd.merge(left=df1,  right=df2, left_on="Hours", right_index=True, suffixes=("_df1", "_df2"))