Попробуйте соединить их по горизонтали, прежде чем считать?
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» встречается только один раз для каждого столбца. Если это происходит более одного раза, оно будет считать каждое вхождение.
Другой вариант включает stack
:
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
? См. По поводу петель с пандами - Когда мне все равно? .