问题的措辞可能令人困惑,但在以下数据框中,我希望能够选择第一行和最后一行:
dt = [['BOS','SF'],['SF','LA'],['LA','NYC'],['SF','BOS'],
]
my_df= pd.DataFrame(columns = ['Source','destination'], data = dt)
my_df
换句话说,确定成对的行,其中第一行的目标是另一行的源,反之亦然。
看起来很简单的问题,但我想不出任何解决方案。
答案 0 :(得分:0)
忽略两列之间的顺序的一种选择是在其自身内对每一行进行排序,np.sort
可以这样做。然后你可以用这些有序的行形成一个新的数据框。 duplicated
和 keep=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_on
和 merge
参数。)
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)