使用pandas在python中临时加入

时间:2018-04-13 22:55:34

标签: python pandas

我需要在python中计算“时间连接”。我正在使用pandas来阅读和处理数据集。我有两个数据集:

df:

TIME  some_features  LABEL
  1         f          -1
  2         f          -1
  3         f          -1
  5         f          -1
  6         f          -1
  7         f          -1
 10         f          -1
 11         f          -1
 13         f          -1
 15         f          -1

labelDf:

TIME_START  TIME_STOP  LABEL
  2          4           0
  6          8           1
  9         10           2
 11         14           1

我的脚本输出必须是df与labelDf的时间连接,因此:

df:

TIME  some_features  LABEL
  1         f          -1
  2         f           0
  3         f           0
  5         f          -1
  6         f           1
  7         f           1
 10         f           2
 11         f           1
 13         f           1
 15         f          -1

现在我正在使用一个非常简单的函数,基本上必须查看两个数据集中每一个的每一行:

def temporalJoin(df, labelDf, typeLabel):
    count = 0
    for index, row in labelDf.iterrows():
        for index2, row2 in df.iterrows():
            if(row2.TIME > row.TIME_START and row2.TIME < row.TIME_STOP):
                df.loc[index2, 'LABEL_'+typeLabel] = row.LABEL_START
                count = count +1
    print("Label counts: " + str(count) + "\n")

运行此代码非常慢,我需要为大小超过2GB的数据集多次运行它。由于标签的数据集是非重叠的,因此,当我匹配标签时,一个好的开始是打破循环,但是,我不喜欢这个解决方案,并且它并没有真正解决问题,因为初始数据集大于标签一。 最糟糕的情况是标签文件,其中包含初始数据集中每个时间戳的标签,因此我想知道是否有一种方法可以选择并仅为标签数据集中出现的行运行连接。

谢谢。

编辑:我修改了示例以包含两个新细节:

  • 第一件事是TIME的序列没有固定的间隔。因此,可能发生TIME = [1,2,3,5,8,11,13]

  • 其次标签文件不是二进制文件,可能有不可预测的标签数量

EDIT2:

  • labelDf中的不同间隔可以具有相同的标签

1 个答案:

答案 0 :(得分:1)

我希望这种方法会更快:

df.set_index('TIME', inplace=True)

df.update(labelDf.reset_index().melt(id_vars=['index', 'LABEL']). \
          groupby(['index', 'LABEL'])['value']. \
          apply(lambda x: pd.Series(list(range(*list(x))+[max(x)]))). \
          reset_index().set_index('value'))

df
#      some_features  LABEL
# TIME                     
# 1                f   -1.0
# 2                f    0.0
# 3                f    0.0
# 4                f    0.0
# 5                f   -1.0
# 6                f    1.0
# 7                f    1.0

<强>解释

在将重新塑造的数据框传递给.update之前,它会对您的labelDf执行一系列重塑操作(其中没有任何内容)。

首先,融化labelDf

labelDf.melt(id_vars='LABEL')
#    LABEL    variable  value
# 0      0  TIME_START      2
# 1      1  TIME_START      6
# 2      0   TIME_STOP      4
# 3      1   TIME_STOP      8

然后,按LABEL分组,选择value,并应用将TIME_STARTTIME_STOP值放在列表中的lambda,创建一个包含该列表的范围附加列表max以使其包含(例如range(*list([2,4]))+[max([2,4])]返回[2, 3, 4]),并将结果列表传递给pd.Series以将列表拆分为列。因此这个操作的结果是:

labelDf.melt(id_vars='LABEL').groupby('LABEL')['value'].apply( \ 
   lambda x: pd.Series(range(*list(x))+[max(x)]))

......看起来像这样:

# LABEL   
# 0      0    2
#        1    3
#        2    4
# 1      0    6
#        1    7
#        2    8

最后一步是重置索引,然后将其设置为value,在这种情况下,以便传递给.update的数据框如下所示:

#        LABEL  level_1
# value                
# 2          0        0
# 3          0        1
# 4          0        2
# 6          1        0
# 7          1        1
# 8          1        2

请注意,您可以删除level_1列,但这不是必需的 - 因为df中没有此列名称的列,它与结果无关update