熊猫在同一列中获得最常用的值

时间:2019-07-25 13:23:44

标签: python pandas

我有一个仅包含两列user_idchannel的数据集。通道列可以采用来自预定义列表[a,b,c,d]的值。有多行具有相同的user_id。每行可以包含上述任何渠道。

如果我考虑每个用户访问的唯一渠道,哪个设置最常出现?

示例数据框:

>>> df = pd.DataFrame([[1, 'a'], [1, 'b'], [1, 'b'], [1,'b'], [2,'c'], [2,'a'], [2,'a'], [2,'b'], [3,'a'], [3,'b']], columns=['user_id', 'Channel'])
>>> df
   user_id Channel
0        1       a
1        1       b
2        1       b
3        1       b
4        2       c
5        2       a
6        2       a
7        2       b
8        3       a
9        3       b

期望的解决方案:

对于上述示例,

类似于:

  • 对于user_id == 1,唯一渠道的集合为{a, b},并且对该组合计一次。
  • 对于user_id == 2,唯一通道的集合为{a, b, c},并且对该组合计一次。请注意,这不包括这些唯一渠道的任何子集。
  • 对于user_id == 3,唯一渠道的集合为{a, b},并且对该组合计一次。

如果我们为每个user_id计算唯一渠道的一个组合,我们应该得到

>>> df_result = pd.DataFrame([['a,b', 2], ['a,b,c', 1]], columns=['Channels_together', 'n'])
>>> df_result
  Channels_together  n
0               a,b  2
1             a,b,c  1

我想出了一种解决方案,可以旋转表,以便获得user_id和列abc,{{1}然后,如果不是NA,则为每个Channel列分配一个整数,然后对各列求和并将结果转换回每个组合。

我敢肯定有更好的方法可以做到这一点,但是我似乎找不到答案。

2 个答案:

答案 0 :(得分:4)

您可以使用groupby.apply(set),然后使用.value_counts计算值:

df.groupby('user_id')['Channel'].apply(set).value_counts()\
  .reset_index(name='n')\
  .rename(columns={'index':'Channels_together'})

输出

  Channels_together  n
0            {a, b}  2
1         {a, c, b}  1

如果您想要str格式的值,我们可以编写一个lambda函数对集合进行排序并将其转换为字符串:

df.groupby('user_id')['Channel'].apply(lambda x: ', '.join(sorted(set(x)))).value_counts()\
  .reset_index(name='n')\
  .rename(columns={'index':'Channels_together'})

输出

  Channels_together  n
0              a, b  2
1           a, b, c  1

答案 1 :(得分:1)

frozenset

是可哈希的并且可以计数

df.groupby('user_id').Channel.apply(frozenset).value_counts()

(a, b)       2
(a, b, c)    1
Name: Channel, dtype: int64

我们可以根据OP的精确度进行调整

c = df.groupby('user_id').Channel.apply(frozenset).value_counts()
pd.DataFrame({'Channels_together': c.index.str.join(', '), 'n': c.values})

  Channels_together  n
0              a, b  2
1           a, b, c  1

或者

df.groupby('user_id').Channel.apply(frozenset).str.join(', ') \
  .value_counts().rename_axis('Channels_together').reset_index(name='n')

  Channels_together  n
0              a, b  2
1           a, b, c  1