如何按一列分组并计算其他列中的类别数?

时间:2018-11-11 09:27:37

标签: python pandas dataframe pandas-groupby

假设我具有以下数据框:

    name        tags
0   abc (1990)  AB|A|BC
1   def (2000)  BC|AB
2   yz (1990)   A|AB

tags列中的值用竖线分隔。此外,列name中值的格式类似于description (year)。我想计算每年的标签数量,以获得一个Series对象,如下所示:

year    
1990  A     2
      AB    2
      BC    1
2000  AB    1
      BC    1

或等同于DataFrame

    year    tags    count
0   1990    A       2
1   1990    AB      2
2   1990    BC      1
3   2000    AB      1
4   2000    BC      1

我对此有一个解决方案,因为它涉及到定义自定义函数以传递给apply方法,我想知道是否存在更紧凑或更有效的解决方案?

这是我当前的解决方案:

years = df['name'].str.slice(start=-5, stop=-1).rename('year')
new_df = df['tags'].str.split('|', expand=True).join(years)

def count_tags(g):
    return g.drop(columns=['year']).stack().value_counts()

new_df.groupby('year').apply(count_tags)

给出:

year    
1990  A     2
      AB    2
      BC    1
2000  AB    1
      BC    1
dtype: int64

附言。对我来说,year是存储为字符串还是整数都没有关系。

1 个答案:

答案 0 :(得分:1)

使用:

new_df = (df.assign(year=lambda x: x['name'].str[-5:-1])
            .set_index('year')['tags']
            .str.split('|', expand=True)
            .stack()
            .reset_index(name='tags')
            .groupby(['year','tags'])
            .size()
            .reset_index(name='count'))
print (new_df)

   year tags  count
0  1990    A      2
1  1990   AB      2
2  1990   BC      1
3  2000   AB      1
4  2000   BC      1

说明

  1. 对于单行解决方案,请首先使用assign进行切片的新列
  2. 对于year的索引,请使用set_index
  3. 然后将split用于DataFrame,并使用SeriesMultiIndex的{​​{3}}进行整形
  4. 对于MultiIndex中的列,请添加stack
  5. 最后reset_index并汇总groupby,最后sizecount

另一种解决方案:

from itertools import chain

tags = df['tags'].str.split('|')

df1 = pd.DataFrame({
    'tags' : list(chain.from_iterable(tags.values.tolist())), 
    'year' : df['name'].str[-5:-1].repeat(tags.str.len())
})

print (df1)
  tags  year
0   AB  1990
1    A  1990
2   BC  1990
3   BC  2000
4   AB  2000
5    A  1990
6   AB  1990

df2 = df1.groupby(['year','tags']).size().reset_index(name='count')
print (df2)
   year tags  count
0  1990    A      2
1  1990   AB      2
2  1990   BC      1
3  2000   AB      1
4  2000   BC      1

说明

  1. 通过reset_index创建列表
  2. 通过split
  3. 获取列表的长度
  4. 最后len列并展平
  5. repeat并汇总size