假设我具有以下数据框:
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
是存储为字符串还是整数都没有关系。
答案 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
说明:
assign
进行切片的新列year
的索引,请使用set_index
split
用于DataFrame,并使用Series
将MultiIndex
的{{3}}进行整形stack
reset_index
并汇总groupby
,最后size
列count
的另一种解决方案:
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
说明:
reset_index
创建列表split
len
列并展平repeat
并汇总size