按组划分的唯一值百分比

% of Unique Values by Group

我想创建下面的列 Stories_% 来对唯一值 % 进行分类。

    SubID   Stories   Stories_%
0   102F2   2         1 (20%), 2 (80%)
1   102F2   2         1 (20%), 2 (80%)
2   102F2   2         1 (20%), 2 (80%)
3   102F2   2         1 (20%), 2 (80%)
4   102F2   1         1 (20%), 2 (80%)
5   132F2   2         1 (60%), 2 (40%)
6   132F2   1         1 (60%), 2 (40%)
7   132F2   1         1 (60%), 2 (40%)
8   132F2   2         1 (60%), 2 (40%)
9   132F2   1         1 (60%), 2 (40%)

我会删除重复项并删除 Stories 所以最终的 table 看起来像这样:

    SubID   Stories_%
0   102F2   1 (20%), 2 (80%)
1   132F2   1 (60%), 2 (40%)

我首先创建了一个包含所有唯一值的列表(如下):

unique_stories = df.groupby(["SubID"])['Stories'].unique().astype(int)
unique_stories
SubID
001C5        ['2']
001C6        ['2']
002I2        ['2']
004C6        ['2']
005L2        ['2']
           ...    
709E1    ['1' '2']
725E1    ['2' '1']
730E1    ['2' '1']

我遇到的问题是获取每个唯一计数的 %s。

我试过了...

df.groupby(['SubID'])['Stories'].count()

...但这只会创建总计数,而不是该类别中每个唯一值的计数。

我研究了很多帖子,但只能显示整个列的总计数、唯一值计数和唯一值计数,而不是按组等。

有没有办法做到这一点?

方法一:可以使用groupby+value_counts

s = df.groupby('SubID')['Stories']\
      .value_counts(normalize=True, sort=False).map('{:.0%}'.format)

(s.index.get_level_values(1).astype(str) + ' (' + s + ')')\
   .groupby(level=0).agg(','.join).reset_index(name='Stories %')

方法 2: 或者你可以使用 Counter 来自 collections:

def normalize():
    d = {}
    for i, g in df.groupby('SubID'):
        c = Counter(g['Stories'])
        d[i] = ', '.join(f'{k} ({v / sum(c.values()):.0%})'
                         for k, v in c.items())
    return d

pd.Series(normalize(), name='Stories %').rename('SubID').reset_index()

   SubID        Stories %
0  102F2  1 (20%),2 (80%)
1  132F2  1 (60%),2 (40%)

如果您接受存储相同信息的稍微不同的格式,但利用了 MultiIndex(这将使未来的操作和计算更简单),那么我们可以使用 gropuby + size 然后 sum.

s = df.groupby(['SubID', 'Stories']).size()
s = s/s.sum(level=0)  # Divide by the total number within each `'SubID'`

SubID  Stories
102F2  1          0.2
       2          0.8
132F2  1          0.6
       2          0.4
dtype: float64