【问题标题】:Intersection / subset of pandas string columns熊猫字符串列的交集/子集
【发布时间】:2019-06-10 20:10:57
【问题描述】:

我有一个带有以下结构的支付的 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

我如何从中找到“封闭成员”支付网络?

例如,如果我想找到一个数据子集,其中仅包含 {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()应该是一样的。

【问题讨论】:

  • 这是一个图论问题,您可以使用 networkx 和 subgraphs 方法。如果您添加了具有预期结果的更完整的数据。我相信 Stack Overflow 社区可以提供帮助。
  • 谢谢斯科特,我怀疑事情不会这么简单。你知道这种特殊的问题叫什么吗?我对networkx有一些经验,并且会自己看。
  • 您可能会找到一些可以使其更容易的设置逻辑。祝你好运。
  • 我在下面发布了一种解决方案的方法(对我有用)。最后,使用 networkx 库并不是绝对必要的,尽管它可能更容易。

标签: python pandas networkx graph-theory intersection


【解决方案1】:

这是您在最大人数中寻找的内容

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

【讨论】:

  • 感谢 Tal,但这并没有返回预期的结果。
【解决方案2】:

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

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

【讨论】:

  • 感谢 PMende,但这似乎不起作用。我尝试了一些非常相似的方法:common_users = np.array(np.intersect1d(df.seller.values, df.buyer.values).tolist()),然后按照您的建议:df_subset = df[df.seller.isin(common_users) & df.buyer.isin(common_users)]。但是,结果集 df_subset.seller.unique()df_subset.buyer.unique() 仍然彼此不同。
【解决方案3】:

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

首先,让我们定义一个与问题中类似的 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 语句,然后是 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

【讨论】:

    猜你喜欢
    • 2018-01-02
    • 2021-10-12
    • 1970-01-01
    • 2014-04-05
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    相关资源
    最近更新 更多