pandas 字符串列的交集/子集

Intersection / subset of pandas string columns

我有一个 pandas 数据框,其付款结构如下:

>> print(df)

id      time      amount      seller     buyer
-------------------------------------------------
1       07:01     16.00       Jack       Rose
2       07:03     14.00       Alice      Bob
3       07:05     95.00       Jim        Larry
...     ...       ...         ...        ...
9999    18:16     81.00       Rose       Alice

如何从中找到 "closed-members" 支付网络?

例如,如果我想找到只包含{Rose、Alice、Jim}彼此之间严格付款的数据子集,则以下可能有效:

members = ['Rose', 'Alice', 'Jim']
df_subset = df[df.seller.isin(members) & df.buyer.isin(members)]

但是如何检索最大的此类网络?即不仅针对 3 个人,而且针对数据框中的最大可能人数?

我已经尝试过以下变体:

df_subset = df[df.seller.isin(df.buyer.unique())]
df_subset = df_subset[df_subset.buyer.isin(df_subset.seller.unique())]

然而,这并不成功,因为之后 df_subset.seller.unique()df_subset.buyer.unique() 不一样。

如有任何帮助,我们将不胜感激。

相信最后df_subset.seller.unique()df_subset.buyer.unique()应该是一样的

这就是你要找的最大人数

a = df[df.seller].drop_duplicates()
b = df[df.buyer].drop_duplicates()
result = pd.concat([a,b])

IIUC,下面应该做你想做的:

common_users = set(df["buyer"]).intersection(df["seller"])
df_subset = df[df["buyer"].isin(common_users) & df["seller"].isin(common_users)]

以下解决方案似乎有效。我将提供一个沙盒解决方案,因为它可能对其他人有用。

首先,让我们定义一个与问题中类似的 pandas 数据框:

# generates strings to be used as names, e.g.: 'hlddldxhys'
def randomString(stringLength=10):
    letters = string.ascii_lowercase
    return ''.join(random.choice(letters) for i in range(stringLength))

# let's generate a set of 600 names
participants = [];
for k in range(600):
    participants.append(randomString())

# from the generated set, draw 1000 sellers and buyers
seller = np.random.choice(participants, 1000)
buyer = np.random.choice(participants, 1000)

# construct pandas data frame
df = pd.DataFrame([seller, buyer]).T
df.columns = ['seller', 'buyer']

查看结果数据框 print(df):

     seller       buyer
----------------------------
0    bpzroghaxp  evvhhlbiys
1    qsopxbirgn  lwwljadfwg
2    cnllyrzjiz  opbvoodpgw
3    hkzafylzst  slfqtwdeak
...    ...        ...
999  natqsscnlk  ftvjvgtala

虽然有些人暗示了一个解决方案(来自 PMende、Tal Avissar 和我自己的回复),但它似乎确实有效 - 但只是迭代,其中每次迭代df = df[df.seller.isin(df.buyer.unique()) & df.buyer.isin(df.seller.unique())] df.seller.unique()df.buyer.unique() 的集合变得更加相似。重复此操作直到它们相同(请参阅最后一个 if-statement,然后是 break):

while(True):
    df = df[df.seller.isin(df.buyer.unique()) & df.buyer.isin(df.seller.unique())]
    if len(df.seller.unique()) == len(df.buyer.unique()):
        if (np.sort(df.seller.unique()) == np.sort(df.buyer.unique())).all() == True:
            break

最终检查确认,df.seller.unique()df.buyer.unique() 的长度相同,组成也相同:

>> len(df.seller.unique()), len(df.buyer.unique())
(281, 281)

>> (np.sort(df.seller.unique()) == np.sort(df.buyer.unique())).all()
True

下图显示了 df.seller.unique()df.buyer.unique() 的集合如何随着循环的每次迭代变得彼此相似:

See also charts: visualisation of solution