如何计算每个组中最频繁的组合

时间:2019-05-20 15:28:53

标签: python pandas

我有一个熊猫数据框,其中的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也将非常有帮助。

4 个答案:

答案 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