Python 将数据帧的行转换为可编辑的字符串列表

Python 将数据帧的行转换为可编辑的字符串列表,python,list,pandas,intersection,iterable,Python,List,Pandas,Intersection,Iterable,假设我有一个数据框df,它有两列,一个用户ID和一个他们购买的产品 df USER_ID | PRODUCT 1 a 1 b 1 c 2 d 2 a 2 k 我想将这个数据帧转换成一个新的数据帧df2,其中每一行是一个用户,产品聚合成一个字符串列表 df2 USER_ID |

假设我有一个数据框df,它有两列,一个用户ID和一个他们购买的产品

df
USER_ID     |     PRODUCT
1                 a
1                 b
1                 c
2                 d
2                 a
2                 k
我想将这个数据帧转换成一个新的数据帧df2,其中每一行是一个用户,产品聚合成一个字符串列表

df2
USER_ID     |     PRODUCT
1                 [a,b,c]
2                 [d,a,k]
最后,我希望能够找到两个用户的产品列表之间的交集

我可以创建第二个数据帧,但我使用的方法会产生一个不知何故不可编辑的列表

具体而言,我:
 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]。我做错了什么

这就是你想要的吗

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
或使用:


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

您可以执行
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']

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

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)}
试试这个:

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

为了更直接地回答您的问题“我做错了什么?”,我很难说,因为当我按照您上面所写的代码进行操作时,生成的
df2
没有列
产品
。你遗漏了一些代码吗?@James使用熊猫交叉表。。。见下文。
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