将 pandas Dataframe 的行转换为可迭代的字符串列表
Convert rows of pandas Dataframe into an iterable list of strings
假设我有一个数据框 df,它有 2 列,一个 USER_ID 和一个他们购买的产品。
df
USER_ID | PRODUCT
1 a
1 b
1 c
2 d
2 a
2 k
我想将这个 DataFrame 转换成一个新的 DataFrame,df2,其中每一行都是一个用户,产品被聚合到一个字符串列表中。
df2
USER_ID | PRODUCT
1 [a,b,c]
2 [d,a,k]
最后,我希望能够找到两个用户的 PRODUCT 列表之间的交集。
我能够创建第二个数据框,但我使用的方法导致列表无法迭代。
具体来说,我是这样做的:
df2 = df1.groupby(‘USER_ID)[‘产品’].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
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
因为您很可能会在使用此数据模型时遇到很多困难(我的意思是在列中列出列表)
您可以执行 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
假设我有一个数据框 df,它有 2 列,一个 USER_ID 和一个他们购买的产品。
df
USER_ID | PRODUCT
1 a
1 b
1 c
2 d
2 a
2 k
我想将这个 DataFrame 转换成一个新的 DataFrame,df2,其中每一行都是一个用户,产品被聚合到一个字符串列表中。
df2
USER_ID | PRODUCT
1 [a,b,c]
2 [d,a,k]
最后,我希望能够找到两个用户的 PRODUCT 列表之间的交集。
我能够创建第二个数据框,但我使用的方法导致列表无法迭代。
具体来说,我是这样做的: df2 = df1.groupby(‘USER_ID)[‘产品’].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
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
因为您很可能会在使用此数据模型时遇到很多困难(我的意思是在列中列出列表)
您可以执行 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