Python 在多个字符串列中统计字符串的出现次数
我有一个名为Python 在多个字符串列中统计字符串的出现次数,python,string,pandas,dataframe,Python,String,Pandas,Dataframe,我有一个名为df的数据框,看起来与此类似(除了“mat_deliver”列的数量增加到mat_deliver_8之外,在Client_ID和mat_deliver_1之间有几百个客户端和许多其他列,我在这里对其进行了简化) 我想创建一个名为xxx\u count的新列,计算xxx出现在mat\u deliver\u 1、mat\u deliver\u 2、mat\u deliver\u 3和mat\u deliver\u 4中的次数。这些值应如下所示: Client_ID mat_deliv_
df
的数据框,看起来与此类似(除了“mat_deliver”列的数量增加到mat_deliver_8之外,在Client_ID
和mat_deliver_1
之间有几百个客户端和许多其他列,我在这里对其进行了简化)
我想创建一个名为xxx\u count
的新列,计算xxx
出现在mat\u deliver\u 1
、mat\u deliver\u 2
、mat\u deliver\u 3
和mat\u deliver\u 4
中的次数。这些值应如下所示:
Client_ID mat_deliv_1 mat_deliv_2 mat_deliv_3 mat_deliv_4 xxx_count
C1019876 xxx,yyy,zzz aaa,xxx,bbb xxx ddd 3
C1018765 yyy,zzz xxx xxx None 2
C1017654 yyy,xxx aaa,bbb ccc ddd 1
C1016543 aaa,bbb ccc None None 0
C1015432 yyy None None None 0
我尝试了以下代码:
df = df.assign(xxx_count=df.loc[:, "mat_deliv_1":"mat_deliv_4"].\
apply(lambda col: col.str.count('xxx')).fillna(0).astype(int))
但它不产生计数,只产生一个二进制变量,其中0
=没有xxx
的情况,1
=四列mat\u deliver
中至少有一列存在xxx
注意:这是一个关于这里所问问题的后续问题:在数数之前试着将它们水平连接起来
df['counts'] = (df.loc[:, "mat_deliv_1":"mat_deliv_4"]
.fillna('')
.agg(','.join, 1)
.str.count('xxx'))
df
Client_ID mat_deliv_1 mat_deliv_2 mat_deliv_3 mat_deliv_4 counts
0 C1019876 xxx,yyy,zzz aaa,bbb,xxx xxx ddd 3
1 C1018765 yyy,zzz xxx xxx NaN 2
2 C1017654 yyy,xxx aaa,bbb ccc ddd 1
3 C1016543 aaa,bbb ccc NaN NaN 0
4 C1019876 yyy NaN NaN NaN 0
假设“xxx”在每列中仅出现一次,则此操作将有效。如果发生多次,则会计算每次发生的次数
另一个选项涉及堆栈:
df['counts'] = (
df.loc[:, "mat_deliv_1":"mat_deliv_4"].stack().str.count('xxx').sum(level=0))
df
Client_ID mat_deliv_1 mat_deliv_2 mat_deliv_3 mat_deliv_4 counts
0 C1019876 xxx,yyy,zzz aaa,bbb,xxx xxx ddd 3
1 C1018765 yyy,zzz xxx xxx NaN 2
2 C1017654 yyy,xxx aaa,bbb ccc ddd 1
3 C1016543 aaa,bbb ccc NaN NaN 0
4 C1019876 yyy NaN NaN NaN 0
使用str.contains
,可以很容易地将其修改为只计算第一次出现的次数:
df['counts'] = (
df.loc[:, "mat_deliv_1":"mat_deliv_4"].stack().str.contains('xxx').sum(level=0))
如果“xxx”可能是子字符串,则首先拆分,然后计数:
df['counts'] = (df.loc[:, "mat_deliv_1":"mat_deliv_4"]
.stack()
.str.split(',', expand=True)
.eq('xxx')
.any(1) # change to `.sum(1)` to count all occurrences
.sum(level=0))
对于性能,请使用列表:
df['counts'] = [
','.join(x).count('xxx')
for x in df.loc[:, "mat_deliv_1":"mat_deliv_4"].fillna('').values
]
df
Client_ID mat_deliv_1 mat_deliv_2 mat_deliv_3 mat_deliv_4 counts
0 C1019876 xxx,yyy,zzz aaa,bbb,xxx xxx ddd 3
1 C1018765 yyy,zzz xxx xxx NaN 2
2 C1017654 yyy,xxx aaa,bbb ccc ddd 1
3 C1016543 aaa,bbb ccc NaN NaN 0
4 C1019876 yyy NaN NaN NaN 0
为什么循环比使用
str
方法或apply
更快?看 使用str.findall
df.iloc[:,1:].apply(lambda x : x.str.findall('xxx')).sum(1).str.len()
Out[433]:
0 3
1 2
2 1
3 0
4 0
dtype: int64
您可以使用按
,
拆分,然后在lambda
中使用lambda
。此解决方案的优点是,如果xxx
作为yyy
的子字符串存在,则不会看到不正确的结果
df['xxx_count'] = df.filter(like='mat_deliv').apply(lambda x: x.str.split(',')\
.apply(lambda x: 'xxx' in x)).sum(1)
print(df)
Client_ID mat_deliv_1 mat_deliv_2 mat_deliv_3 mat_deliv_4 xxx_count
0 C1019876 xxx,yyy,zzz aaa,bbb,xxx xxx ddd 3
1 C1018765 yyy,zzz xxx xxx None 2
2 C1017654 yyy,xxx aaa,bbb ccc ddd 1
3 C1016543 aaa,bbb ccc None None 0
4 C1019876 yyy None None None 0
或者,最好使用一个函数:
def sum_counts(series, value):
def finder(item, value):
return value in item
return series.str.split(',').apply(finder, value=value)
df['xxx_count'] = df.filter(like='mat_deliv').apply(sum_counts, value='xxx').sum(1)
“然后在lambda中使用lambda”。。。哭internally@coldspeed,哈哈,我也要用一个函数更新了。。。完成。感谢您的回复-但是,在我的df上运行之后,我收到一条错误消息,即.str无法在对象数据类型上运行,因此我选择下面的答案。这非常有效-我使用列表理解来获得最后的建议。非常感谢您的帮助。
count
需要注意的一点是,它将在一个较大的字符串中包含一个匹配的子字符串,例如,xxx
和xxxx
都将计数。如果可以的话,那就好了。如果没有,则需要测试相等性,例如,[sum(1表示“,”中的单词。join(row)。split(“,”)表示df.loc[:,“mat_deliver_1:“mat_deliver_4”)。fillna(“”)。value]
def sum_counts(series, value):
def finder(item, value):
return value in item
return series.str.split(',').apply(finder, value=value)
df['xxx_count'] = df.filter(like='mat_deliv').apply(sum_counts, value='xxx').sum(1)