【问题标题】:Convert rows of pandas Dataframe into an iterable list of strings将 pandas Dataframe 的行转换为可迭代的字符串列表
【发布时间】:2016-10-07 17:34:57
【问题描述】:

假设我有一个数据框 df,它有 2 列,一个 USER_ID 和一个他们购买的 PRODUCT。

df
USER_ID     |     PRODUCT
1                 a
1                 b
1                 c
2                 d
2                 a
2                 k

我想将此 DataFrame 转换为新的 df2,其中每一行是一个用户,并且产品被聚合成一个字符串列表。

df2
USER_ID     |     PRODUCT
1                 [a,b,c]
2                 [d,a,k]

最后,我希望能够找到两个用户的 PRODUCT 列表之间的交集。

我能够创建第二个数据框,但我使用的方法导致列表无法迭代。

具体来说,我会: df2 = df1.groupby('USER_ID)['PRODUCT'].agg(lambda x: x.tolist())

这给了我一个我转换回数据框的系列。

df2 = df2.to_frame()

这给了我正在寻找的 df2,但每个产品列表的长度 = 1,因此我无法将 1 与另一个进行比较以找到产品的交集。例如,当我执行时:

s1 = df2.PRODUCT[df2.USER_ID == 1] 
s2 = df2.PRODUCT[df2.USER_ID == 2]

common_elements = list(set(s1).intersection(set(s2)))
common_elements

结果是一个空列表而不是 [a]。我究竟做错了什么?

【问题讨论】:

  • 要更直接地回答您的问题“我做错了什么?”,我很难说,因为当我按照您在上面编写的确切代码时,生成的 df2 不会有一个专栏PRODUCT。你遗漏了一些代码吗?
  • @James 使用 pandas 交叉表...见下文。

标签: python list pandas intersection iterable


【解决方案1】:

您可以执行groupby,然后找到两个列表之间的交集,如图所示:

>>>df2 = df.groupby('USER_ID')['PRODUCT'].apply(list).reset_index()
>>>df2

   USER_ID    PRODUCT
0        1  [a, b, c]
1        2  [d, a, k]

>>>list(set(df2['PRODUCT'].loc[0]).intersection(df2['PRODUCT'].loc[1]))
['a']

或者用更短的方式:

df2 = df.groupby('USER_ID')['PRODUCT'].apply(list)
>>>list(set(df2.loc[1]).intersection(df2.loc[2]))
['a']

【讨论】:

    【解决方案2】:

    试试这个:

    df3 = pd.crosstab(df2.PRODUCT,df2.USER_ID, margins= True)
    print df3[df3['All']>1]
    
      # USER_ID  1  2  All
       # PRODUCT           
       # a        1  1    2
       # All      3  3    6
    

    我的解决方案与@Nikil 非常相似,因此使用他的。

    df2 = df.groupby('USER_ID')['PRODUCT'].apply(list)
    df2 = df2.reset_index()
    print df2
    
    
    #         USER_ID    PRODUCT
    #    0        1  [a, b, c]
    #    1        2  [d, a, k]
    

    有关交叉表的更多信息,它是一个数据框。

    pd.crosstab(df2.PRODUCT,df2.USER_ID, margins= True)
    
    #    USER_ID  1  2  All
    #    PRODUCT           
    #    a        1  1    2
    #    b        1  0    1
    #    c        1  0    1
    #    d        0  1    1
    #    k        0  1    1
    #    All      3  3    6
    

    【讨论】:

      【解决方案3】:

      这将为您提供一个通用的解决方案来查找任何两个用户产品列表的交集,而无需草率的第二个数据框

      from collections import defaultdict
      
      user1 = 1
      user2 = 2
      products = defaultdict(set)
      
      for record in df.to_dict('records'):
          products[record['USER_ID']].add(record['PRODUCT'])
      
      common_elements = products[user1].intersection(products[user2])]
      print(common_elements)
      

      然后,如果您想要与所有用户对的所有交叉点

      from itertools import combinations
      common_elements = {(x,y): products[x].intersection(products[y]) for x,y in combinations(products.keys(),2)}
      

      【讨论】:

        【解决方案4】:

        这就是你想要的吗?

        In [7]: pd.Series(np.intersect1d(df.loc[df.USER_ID == 1, 'PRODUCT'], df.loc[df.USER_ID == 2, 'PRODUCT']))
        Out[7]:
        0    a
        dtype: object
        

        或使用index.intersection():

        In [18]: (df.set_index('PRODUCT').query('USER_ID == 1').index
           ....:    .intersection(df.set_index('PRODUCT').query('USER_ID == 2').index)
           ....:    .to_series()
           ....: )
        Out[18]:
        PRODUCT
        a    a
        Name: PRODUCT, dtype: object
        

        PS 我不会将您的 df 转换为 df2,因为您很可能会在使用此数据模型时遇到很多困难(我的意思是在列中有列表)

        【讨论】:

          猜你喜欢
          • 2020-11-20
          • 2018-07-13
          • 1970-01-01
          • 2021-04-14
          • 2014-05-31
          • 2020-09-03
          • 2020-04-12
          • 1970-01-01
          • 2014-01-05
          相关资源
          最近更新 更多