【问题标题】:Uncommon values from two data frames by rows in python在python中按行来自两个数据帧的不常见值
【发布时间】:2020-12-03 22:59:00
【问题描述】:

我有两个数据框 df1df2。两者中的第一列都是客户 ID,它是 int,但其他列包含各种字符串值。我想为每个客户 ID 生成一个新的数据框 df3,其中包含一组在 df2 中找到但在 df1 中没有的值。

例子:

df1

     v1 v2 v3 v4
cust            
1     A  B  B  A
2     A  A  A  A
3     B  B  A  A
4     B  C  A  A

df2

     v1 v2 v3 v4
cust            
1     A  A  C  B
2     A  A  C  B
3     C  B  B  A
4     C  B  B  A

预期输出:

cust
1       {C}
2    {B, C}
3       {C}
4        {}

【问题讨论】:

  • 请不要添加图片,请以可以复制到 Python 脚本中的方式添加数据框。
  • @DaniMesejo 我是新来的。我尝试了其他甲酸盐,但它不起作用。希望我能得到你的帮助。

标签: python pandas dataframe


【解决方案1】:
In [2]: df_2 = pd.DataFrame({"KundelID" : list(range(1,11)),
   ...:               'V1' : list('AACCBBBCCC'),
   ...:               'V2' : list('AABBBCCCAA'),
   ...:               'V3' : list('CCBBBBBAAB'),
   ...:               'V4' : list('BBAACAAAAB')})
   ...: df_1 = pd.DataFrame({"KundelID" : list(range(1,11)),
   ...:               'V1' : list('AABBCCCCCC'),
   ...:               'V2' : list('BABCCCCAAA'),
   ...:               'V3' : list('BAAAAABBBB'),
   ...:               'V4' : list('AAAACCCCBB')})

In [3]: df_1
Out[3]: 
   KundelID V1 V2 V3 V4
0         1  A  B  B  A
1         2  A  A  A  A
2         3  B  B  A  A
3         4  B  C  A  A
4         5  C  C  A  C
5         6  C  C  A  C
6         7  C  C  B  C
7         8  C  A  B  C
8         9  C  A  B  B
9        10  C  A  B  B

In [4]: df_2
Out[4]: 
   KundelID V1 V2 V3 V4
0         1  A  A  C  B
1         2  A  A  C  B
2         3  C  B  B  A
3         4  C  B  B  A
4         5  B  B  B  C
5         6  B  C  B  A
6         7  B  C  B  A
7         8  C  C  A  A
8         9  C  A  A  A
9        10  C  A  B  B

In [7]: pd.DataFrame({"KundeID" : df_2.KundelID,
   ...:             'Not-in-df_1' : [','.join([i for i in df_2_ if not i in df_1_]) if [i for i in df_2_ if not i in df_1_] else None for df_1_,df_2_ in zip(df_1.T[1:].apply(np.unique), df_2.T[1:].apply(np.unique))]})
Out[7]: 
   KundeID Not-in-df_1
0        1           C
1        2         B,C
2        3           C
3        4        None
4        5           B
5        6           B
6        7           A
7        8        None
8        9        None
9       10        None


【讨论】:

  • 虽然(根据输出判断)这提供了答案,但您可以通过解释如何获得结果来使您的答案更有价值。也许拆分(和解释)一长串 Python 代码会有所帮助?
【解决方案2】:

想法是将每一行中的所有值转换为set。然后,我们可以为每个客户 ID 设置差异。这避免了循环和列表推导:

df3 = (
    pd
    .concat([
        df1.reindex(index=df2.index).apply(set, axis=1),
        df2.apply(set, axis=1),
    ], axis=1)
    .apply(lambda r: r[1].difference(r[0]), axis=1)
)
print(df3)
# Out:
cust
1       {C}
2    {B, C}
3       {C}
4        {}

注意事项

  1. df1.reindex(index=df2.index) 位是为了防止df1df2 中缺少某些ID。
  2. 将输出转换为其他内容而不是set 是微不足道的。例如 ','.join(r[1].difference(r[0])) 作为 lambda 将生成字符串。

设置

为了便于将来参考,为了便于重现示例,最好提供一些可以直接由 SO-ers 复制/粘贴的代码,以便快速开始解决您的问题。

df1 = pd.read_csv(io.StringIO("""
1 A B B A
2 A A A A
3 B B A A
4 B C A A
"""), sep=' ', names='cust v1 v2 v3 v4'.split()).set_index('cust')

df2 = pd.read_csv(io.StringIO("""
1 A A C B
2 A A C B
3 C B B A
4 C B B A
"""), sep=' ', names='cust v1 v2 v3 v4'.split()).set_index('cust')

【讨论】:

    【解决方案3】:

    您将每个数据帧转换为一系列集合,然后利用 pandas 系列中的 intrinsic data alignment 跨系列执行集合操作:

    df2.apply(set, axis=1) - df1.apply(set, axis=1)
    

    输出:

    cust
    1       {C}
    2    {C, B}
    3       {C}
    4        {}
    dtype: object
    

    如果您想跨数据集使用symmetric difference元素在集合或其他元素中,但不能同时在两者中),那么最好使用pd.concat

    dfs = [df1, df2]
    pd.concat([df.apply(set, 1) for df in dfs], 1).apply(lambda x: x[0]^x[1], 1)
    

    这里的 1 代表axis=1。此外,用set.symmetric_difference(*x) 替换x[0]^x[1] 也应该可以。

    有趣的是,Series_A ^ Series_B 没有按预期工作,而是(显然)返回一个 bool Series,告诉我们集合操作的返回值是否为空。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-07
      • 1970-01-01
      • 1970-01-01
      • 2022-11-25
      • 2018-12-30
      • 2019-12-08
      相关资源
      最近更新 更多