熊猫识别两列具有相同字符串的行

时间:2021-07-01 18:48:53

标签: python pandas

问题的措辞可能令人困惑,但在以下数据框中,我希望能够选择第一行和最后一行:

dt = [['BOS','SF'],['SF','LA'],['LA','NYC'],['SF','BOS'],
      ]
my_df= pd.DataFrame(columns = ['Source','destination'], data = dt)
my_df

换句话说,确定成对的行,其中第一行的目标是另一行的源,反之亦然。

看起来很简单的问题,但我想不出任何解决方案。

4 个答案:

答案 0 :(得分:0)

忽略两列之间的顺序的一种选择是在其自身内对每一行进行排序,np.sort 可以这样做。然后你可以用这些有序的行形成一个新的数据框。 duplicatedkeep=False 会将所有重复的行标记为 True,我们可以将其用作掩码来索引原始数据帧:

rows_sorted_df = pd.DataFrame(np.sort(df))
dups = rows_sorted_df.duplicated(keep=False)
result = df[dups]

得到

>>> rows_sorted_df

     0    1
0  BOS   SF
1   LA   SF
2   LA  NYC
3  BOS   SF

>>> dups

0     True
1    False
2    False
3     True

>>> result

  Source destination
0    BOS          SF
3     SF         BOS

答案 1 :(得分:0)

如果将列分成单独的数据框,则可以合并它们以仅获取匹配的行。

(在本例中,我将每个 df 中的列重命名为“code”;或者,您可以在 right_on 调用中指定 left_onmerge 参数。)

s = my_df['Source'].reset_index().rename(columns={'Source':'code', 'index':'source_index'})
d = my_df['destination'].reset_index().rename(columns={'destination':'code', 'index':'dest_index'})

sd = pd.merge(s, d)


In: sd
Out: 
   source_index code  dest_index
0             0  BOS           3
1             1   SF           0
2             3   SF           0
3             2   LA           1

答案 2 :(得分:0)

这就是我想到的,并考虑了加入。

    import pandas as pd
    dt = [['BOS', 'SF'], ['SF', 'LA'], ['LA', 'NYC'], ['SF', 'BOS'],
          ]
    df = pd.DataFrame(columns=['Source', 'destination'], data=dt)
    df
<头>
来源 目的地
0 BOS SF
1 SF 洛杉矶
2 洛杉矶 纽约
3 SF BOS

计算目标 -> 源之间的匹配

    left = df.copy()
    right = df.copy().set_index("Source")
    
    dest_to_source = left.join(right, on=[left["destination"]], 
    lsuffix='_original', rsuffix="_matched", how="inner")
    # pandas joins do weird things to the column names, so renaming and reordering
    dest_to_source.columns = ["Source_matched","Source_original","destination_original","destination_matched"]
    dest_to_source = dest_to_source[["Source_original","destination_original","Source_matched","destination_matched"]]
    dest_to_source

这是结果:

<头>
Source_original destination_original Source_matched destination_matched
0 BOS SF SF BOS
1 SF 洛杉矶 洛杉矶 SF
2 洛杉矶 纽约 纽约 洛杉矶
3 SF BOS BOS SF

然后您可以对源 -> 目标执行相同的操作(对于问题的“反之亦然”部分)\

    right = df.copy().set_index("destination")
    source_to_dest = left.join(right, on=[left["Source"]], lsuffix='_original',rsuffix='_matched', how="inner")
    source_to_dest.columns = ["destination_matched","Source_original","destination_original","Source_matched"]
    source_to_dest = source_to_dest[["Source_matched","destination_matched","Source_original","destination_original"]]
    source_to_dest
<头>
Source_matched destination_matched Source_original destination_original
0 SF BOS BOS SF
1 BOS SF SF 洛杉矶
3 BOS SF SF BOS
2 SF 洛杉矶 洛杉矶 纽约

答案 3 :(得分:0)

IMO,最好的方法是像这样使用 join

import pandas as pd

dt = [
  ['BOS','SF'],
  ['SF','LA'],
  ['LA','NYC'],
  ['SF','BOS'],
]

my_df = pd.DataFrame(columns = ['Source','destination'], data = dt)
source_df = my_df.set_index('Source')
dest_df = my_df.set_index('destination')
joined_df = source_df.join(dest_df)

print(joined_df)

这是输出(一开始有点混乱):

    destination Source
BOS          SF     SF
LA          NYC     SF
SF           LA    BOS
SF          BOS    BOS

如果我们更深入地思考它是有道理的。让我们从输入中取出这些行:

  ['SF','LA'],
  ['LA','NYC'],

我们的连接将这些行转换为“源 -> 中间 -> dest”,或“SF -> LA -> NYC”。查看我们的结果表

    destination Source
LA          NYC     SF

我们可以将其读作“从源列 'SF' 到目标列 'NYC' 通过行 'LA' 的索引。如果您希望数据框更具可读性,可以添加以下内容:

joined_df.index.name = 'middle'
joined_df = joined_df.reset_index()
print(joined_df)