将DataFrames中的行与行条件逐行合并的有效方法是什么?

时间:2017-03-06 00:19:44

标签: pandas join dataframe

我正在使用来自两个系统的数据加入两个表。两个df之间的简单Pandas 合并将不会遵循更复杂的规则(除非我使用它错误,不理解进程合并正在实现 - 非常可能)。

我拼凑了一个玩具解决方案,让我用itertuples解包两个df,根据值验证匹配,然后重新打包到一个数据帧中:

df1:            df2:
   A   X           B   Y
0  1  10        0  2  10
1  5  15        1  4  15
                2  6  15

df1 = pd.DataFrame(data1,columns=['A','X'])
df2 = pd.DataFrame(data2,columns=['B','Y'])
df3 = pd.DataFrame(index=['A','X','B','Y'])
i = -1

for rowA in df1.itertuples(index=False):
    i += 1
    for rowB in df2.itertuples(index=False):
        A,X = rowA
        B,Y = rowB
        if (B > A) & (X==Y):
            df3[i] = list(rowA+rowb)
        else:
            continue

print(df3.transpose())

   A   X  B   Y
0  1  10  2  10
1  5  15  6  15

我天真的做法效率低下

嵌套的for()循环是低效的,因为我正在为data1的每个条目迭代data2 / df2。一旦我与data2 / df2很好地匹配,就应删除该行。

// UPDATE(显示我问题的来源)

我正在使用的数据类型的示例合并了两个不共享任何密钥或其他序列化ID的独立系统。由于我不能完全匹配,我必须依赖逻辑/算术运算和消除过程。

在以下示例中,简单的pandas.merge在Line3上失败,因为Time1<时间2。

   Time1,               Total1 ... Time2,               Total2, error
1, 2017-02-19 08:03:00, 15.00  ... 2017-02-19 08:02:00,  15.00, 0
2, 2017-02-19 08:28:00, 33.00  ... 2017-02-19 08:27:00,  33.00, 0
3, 2017-02-19 08:40:00, 20.00  ... 2017-02-19 10:06:00,  20.00, 1
4, 2017-02-19 10:08:00, 20.00  ... 2017-02-19 10:16:00,  20.00, 1
[...]

应该发生的事情是这样的:

   Time1,               Total1 ... Time2,               Total2, error
1, 2017-02-19 08:03:00, 15.00  ... 2017-02-19 08:02:00,  15.00, 0
2, 2017-02-19 08:28:00, 33.00  ... 2017-02-19 08:27:00,  33.00, 0
3, 2017-02-19 08:40:00, 20.00  ... NaN,                  NaN,   NaN
4, 2017-02-19 10:08:00, 20.00  ... 2017-02-19 10:06:00,  20.00, 0
[...]

// UPDATE2 我已经在答案中推荐了merge_asof()join()的几种排列方式。每个方法也按照docs的指示进行排序。假设我已经正确实现了每个,以下百分比是True匹配规则((time1> = time2)&(Total1 == Total2)中的53条记录)测试集使用以下三种方法中的每一种:

| type                  | 'date'   | 'total'   | both   |
|-----------------------|----------|-----------|--------|
| merg_asof sort (time) | .7924    | .9245     | .7169  |
| merg_asof (time,total)| .7735    | .6981     | .6226  |
| intertup (time,total) | .8301    | .8301     | .8301  |
| join ind (time)       | na       | na        | na     |

加入需要共享密钥,对吗?文档中的on子句声明,“调用者中的列连接其他索引,否则连接index-on-index。如果给定的列数倍,则传递的DataFrame必须具有MultiIndex。“

我尝试了join多指数(时间,总数)和正常(时间)。问题是,无论你加入什么,加入clobbers。没有什么可以执行错误分析,因为这些索引合并为一个。

我天真的intertuple解决方案(上图)只产生了完美的匹配,但解决方案仍然需要一个错误匹配的收集器。

2 个答案:

答案 0 :(得分:0)

df3 = df1.join(df2)没有做你想做的事情?

答案 1 :(得分:0)

如果我正确理解你的逻辑,那应该这样做:

time1 = pd.to_datetime(['2/19/17 8:03:00', '2/19/17 8:28:00', '2/19/17 8:40:00', '2/19/17 10:08:00'])
time2 = pd.to_datetime(['2/19/17 8:02:00', '2/19/17 8:27:00', '2/19/17 10:06:00', '2/19/17 10:16:00'])

df1 = pd.DataFrame({'Time1':time1, 'Total1':[15.00, 33.00, 20.00, 20.00]})
df2 = pd.DataFrame({'Time2':time2, 'Total2':[15.00, 33.00, 20.00, 20.00], 'error':[0,0,1,1]})

df3 = pd.merge_asof(df1, df2, left_on = 'Time1', right_on = 'Time2')
df3.loc[df3['Time2'].duplicated(), ['Time2', 'Total2', 'error']] = None

输出:

                Time1  Total1               Time2  Total2  error
0 2017-02-19 08:03:00    15.0 2017-02-19 08:02:00    15.0    0.0
1 2017-02-19 08:28:00    33.0 2017-02-19 08:27:00    33.0    0.0
2 2017-02-19 08:40:00    20.0                 NaT     NaN    NaN
3 2017-02-19 10:08:00    20.0 2017-02-19 10:06:00    20.0    1.0