我有一个熊猫数据框,其中的post_ID和tag_ID的格式很长(一个帖子到多个标签)。
+---------+--------+
| post_ID | tag_ID |
+---------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 4 |
| 2 | 6 |
| 3 | 1 |
| 4 | 5 |
| 4 | 6 |
| ... | ... |
+---------+--------+
我的问题是:当查看按post_ID分组的标签时,最常见的两个标签组合是什么? 结果,我希望有一个包含如下结果的框架:
+---------------------+-----+
| tag_ID_combinations | n |
+---------------------+-----+
| 1,2 | 50 |
| 3,4 | 200 |
| 5,6 | 20 |
+---------------------+-----+
post_ID 1的标签1,2和3如果可能的话应计为1,2,1,3和2,3。 但是聚合像1,2,3-1x; 1,4,6-1x; 1-1x和5,6-1x也将非常有帮助。
答案 0 :(得分:1)
如果您仅想按post_ID汇总出现次数,则这里是一种解决方案。 此解决方案将根据您的示例进行计算(post_id == 1):
[1、2、3]:1
,并非所有可能的组合:
[1,2] = 1,[1,3] = 1,[2,3] = 1
df = df.groupby('post_ID')['tag_ID'].apply(list)
df = pd.DataFrame(df).reset_index()
# only if you want to throw out single occurrences
df = df[df['tag_ID'].map(len) > 1]
# cast the sorted lists to string
df['tag_ID_AS_STRING'] = [str(sorted(x)) for x in df['tag_ID']]
result = df['tag_ID_AS_STRING'].value_counts()
答案 1 :(得分:0)
您可以使用group by。您可以使用以下
df.groupby(['post_ID', 'tag_ID']).count()
这将生成一个以组合为索引的表。
另一种方法是创建组合
df['combo'] = df[['post_ID', 'tag_ID']].agg(tuple, axis=1)
然后在combo
字段上进行分组。
以上两项都需要更多的工作,我相信您可以从上面完成。
答案 2 :(得分:0)
您提到的第二种聚合非常容易获得:
df = pd.DataFrame({'post_ID': [1, 1, 1, 2, 2, 2, 3, 4, 4],
'tag_ID': [1, 2, 3, 1, 4, 6, 1, 5, 6]})
df.groupby('post_ID').tag_ID.unique().value_counts()
# [1] 1
# [1, 4, 6] 1
# [1, 2, 3] 1
# [5, 6] 1
# Name: tag_ID, dtype: int64
您要求的第一种汇总方法不一致,因此很难回答。对于post_ID
1,您要的是1,2,1,3和2,3,而没有计算元素与自身(1、2、2、2等)的组合。但是对于post_ID
3,您确实说要1-1x,这不是标记的组合。如果后者是一个错误,即使它不是很优雅,您也可以这样做:
首先,获取每个post_ID
的组合:
import itertools
combs_df = df.groupby('post_ID').tag_ID\
.apply(lambda x: list(itertools.combinations(x.tolist(), 2)))
combs_df
# post_ID
# 1 [(1, 2), (1, 3), (2, 3)]
# 2 [(1, 4), (1, 6), (4, 6)]
# 3 []
# 4 [(5, 6)]
# Name: tag_ID, dtype: object
现在,您可以通过将每行的列表放在列表中来使其扁平化:
combs_lst = []
combs_df.apply(lambda x: combs_lst.extend(x))
combs_lst
# [(1, 2), (1, 3), (2, 3), (1, 4), (1, 6), (4, 6), (5, 6)]
现在,简单地将列表作为熊猫系列并进行value_count
:
pd.Series(combs_lst).value_counts()
# (1, 4) 1
# (5, 6) 1
# (1, 6) 1
# (4, 6) 1
# (2, 3) 1
# (1, 3) 1
# (1, 2) 1
# dtype: int64
答案 3 :(得分:0)
您可以将DataFrame.groupby('col').agg(func)
与itertools.combinations
一起使用,以获取所有2种标记组合,然后使用collections.Counter
获得每种组合的出现次数。
from collections import Counter
from itertools import combinations
import pandas as pd
groups = df.groupby('post_ID').agg(lambda g: list(combinations(g, 2)))
combos = pd.DataFrame(
Counter(groups.tag_ID.sum()).items(),
columns=['tag_ID_combos', 'count']
)
下面的示例更改了您问题中的某些数据,因此至少会有多个标签组合出现多次。
from collections import Counter
from itertools import combinations
import pandas as pd
data = [(1,1),(1,2),(1,3),(2,1),(2,3),(2,6),(3,1),(4,3),(4,6)]
df = pd.DataFrame(data, columns=['post_ID', 'tag_ID'])
print(df)
# post_ID tag_ID
# 0 1 1
# 1 1 2
# 2 1 3
# 3 2 1
# 4 2 3
# 5 2 6
# 6 3 1
# 7 4 3
# 8 4 6
groups = df.groupby('post_ID').agg(lambda g: list(combinations(g, 2)))
combos = pd.DataFrame(Counter(groups.tag_ID.sum()).items(), columns=['tag_ID_combos', 'count'])
print(combos)
# tag_ID_combos count
# 0 (1, 2) 1
# 1 (1, 3) 2
# 2 (2, 3) 1
# 3 (1, 6) 1
# 4 (3, 6) 2