匹配数据框之间的行并保留顺序

时间:2019-07-17 15:40:28

标签: python pandas

我在pythonpandas工作。

让我们假设我有一个像这样的数据框:(输入)

    A   B   C
0   2   8   6
1   5   2   5
2   3   4   9
3   5   1   1

我想对其进行处理以最终获得一个新的数据框,该数据框看起来像(预期输出)

    A   B   C
0   2   7   NaN
1   5   1   1
2   3   3   NaN
3   5   0   NaN

要对此进行管理,请执行以下操作:

columns = ['A', 'B', 'C']
data_1 = [[2, 5, 3, 5], [8, 2, 4, 1], [6, 5, 9, 1]]
data_1 = np.array(data_1).T
df_1 = pd.DataFrame(data=data_1, columns=columns)

df_2 = df_1
df_2['B'] -= 1
df_2['C'] = np.nan

df_2现在看起来像这样:

    A   B   C
0   2   7   NaN
1   5   1   NaN
2   3   3   NaN
3   5   0   NaN

现在,我想使用列df_1df_2作为键,在AB之间进行匹配/合并。

我尝试过isin()来做到这一点:

df_temp = df_1[df_1[['A', 'B']].isin(df_2[['A', 'B']])]
df_2.iloc[df_temp.index] = df_temp

但是它给了我与以前相同的df_2,而没有分别匹配5 1 1AB的公共行C

    A   B   C
0   2   7   NaN
1   5   1   NaN
2   3   3   NaN
3   5   0   NaN

如何正确执行此操作?

顺便说一句,要明确一点,匹配不应该像

一样进行
  • df1的第一行-df1的第一行
  • df1的第二行-df2的第二行
  • df1的第三行-df2的第三行
  • ...

但这必须通过以下方式完成:

  • df1的任意行-df2的任意行

基于指定的列作为键。

我认为这就是上面代码中的isin()无效的原因,因为它以以前的方式进行了过滤/匹配。

另一方面,.merge()可以用后一种方式进行匹配,但是它并不能按照我想要的方式保留行的顺序,而且很难解决。

最后,请记住,对于我的实际数据框,将仅使用2列(例如15列)作为匹配的键,因此最好为较大的数据框提供简洁的内容。

PS

请在下面查看我的答案。

4 个答案:

答案 0 :(得分:1)

某人(我不记得他的用户名)建议以下内容(我认为有效),然后他出于某种原因删除了他的帖子(??!):

df_2=df_2.set_index(['A','B'])

temp = df_1.set_index(['A','B'])

df_2.update(temp)

df_2.reset_index(inplace=True)

答案 1 :(得分:0)

这是我在apply中使用lambda函数的建议。应该可以轻松扩展到更多列进行比较(只需相应地调整cols_to_compare即可)。顺便说一句,在生成df_2时,请确保复制df_1,否则df_2中的更改也将继承到df_1。 因此,首先生成数据:

columns = ['A', 'B', 'C']
data_1 = [[2, 5, 3, 5], [8, 2, 4, 1], [6, 5, 9, 1]]
data_1 = np.array(data_1).T
df_1 = pd.DataFrame(data=data_1, columns=columns)

df_2 = df_1.copy()  # Be sure to create a copy here
df_2['B'] -= 1
df_2['C'] = np.nan

现在我们“扫描” df_1以查找感兴趣的行:

cols_to_compare = ['A', 'B']
df_2['C'] = df_2.apply(lambda x: 1 if any((df_1.loc[:, cols_to_compare].values[:]==x[cols_to_compare].values).all(1)) else np.nan, axis=1)

所要做的是检查df_1的相关列中当前行中的值是否也与此类似。 输出为:

   A  B    C
0  2  7  NaN
1  5  1  1.0
2  3  3  NaN
3  5  0  NaN

答案 2 :(得分:-1)

您可以使用两个for循环来完成此操作:

for row in df_2.iterrows():
    for row2 in df_1.iterrows():
        if [row[1]['A'],row[1]['B']] == [row2[1]['A'],row2[1]['B']]:
            df_2['C'].iloc[row[0]] = row2[1]['C']

答案 3 :(得分:-1)

只需修改您的下一行:

df_temp = df_1[df_1[['A', 'B']].isin(df_2[['A', 'B']])]

具有:

df_1[df_1['A'].isin(df_2['A']) & df_1['B'].isin(df_2['B'])]

效果很好!