使用最近的时间加入数据框并为特定对象填写缺少的时间戳记

时间:2019-01-16 21:28:29

标签: python pandas dataframe

我有两个数据帧。

数据帧1(df1):

1    object_name     time_epoch_ms      source      data
2    a               1538518822490      source_1     some_data
3    b               1538528822490      source_2     some_data
4    b               1538538822490      source_2     some_data
5    b               1538548822490      source_3     some_data
6    b               1538558822490      source_1     some_data
7    c               1538568822490      source_2     some_data
8    c               1538578822490      source_2     some_data
9    c               1538588822490      source_2     some_data
... etc etc

数据帧2(df2):

1    object_name     time_epoch_ms      new_data
2    a               1538518722490      x
3    b               1538528822490      y
4    b               1538518922490      z
5    b               1538519922490      a
6    b               1538598822490      b
7    c               1538548822490      c
8    c               1538538822490      c
9    c               1538528822490      d
... etc etc

这两个表中的条目提供了有关在不同时间点具有object_names的对象的信息。

我想结合这两个表,以便在数据框#1中指定的特定时间使用对象名使用的源来扩充数据框#2。

问题:两个表中的时间戳不完全匹配。表2中存在一些时间戳,表1中不存在。但是,它们应大致对应于小时。表1中缺少一些时间戳,因此“最后可用数据”是最好的。

有没有办法利用熊猫的合并能力执行以下步骤?

  1. 匹配数据帧中的数据,以便df2从中获取“源”数据 基于object_name和time_stamp的df1,以便time_stamp匹配 到最近的小时。
  2. 如果特定时间的数据在df2中,但     不是df1,则从的最后一个可用小时重试源     数据,因此根据存在的数据“填充”该数据     对象。
  3. 如果df2中的对象不在df1中,那么它将获得“空”

我的方法:

我目前正在执行.apply以从df2中获取每一行,并在df1中找到该对象的所有时间戳(如果存在)。然后,我返回最接近的匹配项或null。

我想知道是否有使用pandas的merge或concat功能的更优雅的方式,但是我很难理解在这种情况下如何使用它们以及如何根据小时来处理数据填充和匹配(无需进行单独的预处理就可以在其中获得一个小时列)。

1 个答案:

答案 0 :(得分:1)

通常,Pandas使“等值连接”变得容易,但是其他种类则比较困难。在这种情况下,您很幸运,因为有一个不错的方法叫做merge_asof,它可以满足您的需求。

关于如何设置数据有些古怪,但是MWE是:

from io import StringIO
import pandas as pd

df1 = pd.read_table(StringIO("""1    object_name     time_epoch_ms      source      data
2    a               1538518822490      source_1     some_data_1
3    b               1538528822490      source_2     some_data_2
4    b               1538538822490      source_2     some_data_3
5    b               1538548822490      source_3     some_data_4
6    b               1538558822490      source_1     some_data_5
7    c               1538568822490      source_2     some_data_6
8    c               1538578822490      source_2     some_data_7
9    c               1538588822490      source_2     some_data_8
"""), sep=r"\s+", index_col=0)

df2 = pd.read_table(StringIO("""1    object_name     time_epoch_ms      new_data
2    a               1538518722490      x
3    b               1538528822490      y
4    b               1538518922490      z
5    b               1538519922490      a
6    b               1538598822490      b
7    c               1538548822490      c
8    c               1538538822490      c
9    c               1538528822490      d
"""), sep=r"\s+", index_col=0)

pd.merge_asof(
    df2.sort_values(['time_epoch_ms', 'object_name']),
    df1.sort_values(['time_epoch_ms', 'object_name']),
    by="object_name", on="time_epoch_ms",
    direction='forward',
).sort_values(['object_name', 'time_epoch_ms'])

这回馈:

  object_name  time_epoch_ms new_data    source         data
0           a  1538518722490        x  source_1  some_data_1
1           b  1538518922490        z  source_2  some_data_2
2           b  1538519922490        a  source_2  some_data_2
3           b  1538528822490        y  source_2  some_data_2
7           b  1538598822490        b       NaN          NaN
4           c  1538528822490        d  source_2  some_data_6
5           c  1538538822490        c  source_2  some_data_6
6           c  1538548822490        c  source_2  some_data_6

另请参见Pandas equivalent of SQL non-equi JOIN。还有merge_ordered,但我认为这对您的情况没有帮助。