已编辑:
我有以下数据框
Name Code
Cedric AMMMM
Joe A
Mickael AMMCX
Dupond MMMMMMM
Jean AMMMCMC
我想计算 Code 列中字符出现值的数量。并用字符和出现次数的串联替换值。
我的预期结果如下:
Name Code
Cedric 1A4M
Joe 1A
Mickael 1A2M1C1X
Dupond 7M
Jean 1A3M1C1M1C
我尝试了以下方法:
for index, row in df.iterrows():
for i in "".join(set(row.Code)):
num = test.count(i)
df.loc[index,"Code"] = val + str(num) + i
但是实际上,我有一个超过80万行的巨大数据框。当我执行此代码时,该过程太长了。
我正在寻找一种更好的解决方案。
已编辑:我在数据框中添加了最后一个示例。先前的响应无法处理此示例。我想处理这个用例
感谢您的帮助。
答案 0 :(得分:2)
在f-string
工作于python 3.6+
的情况下使用列表推导功能,并按索引添加sorted
以便不更改顺序:
df['Code'] = [''.join(f'{x.count(i)}{i}' for i in sorted(set(x),key=x.index)) for x in df['Code']]
或使用Counter
:
from collections import Counter
df['Code'] = [''.join(f'{j}{i}' for i, j in Counter(x).items()) for x in df['Code']]
print (df)
Name Code
0 Cedric 1A4M
1 Joe 1A
2 Mickael 1A2M1C1X
3 Dupond 7M
性能:
#[40000 rows x 2 columns]
df = pd.concat([df] * 10000, ignore_index=True)
In [119]: %timeit df['Code'] = [''.join(f'{j}{i}' for i, j in Counter(x).items()) for x in df['Code']]
276 ms ± 9.97 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [120]: %timeit df['Code'] = [''.join(f'{x.count(i)}{i}' for i in sorted(set(x),key=x.index)) for x in df['Code']]
262 ms ± 3.09 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
#U9-Forward solution
In [124]: %timeit df['Code']=df['Code'].apply(lambda x: ''.join([''.join(map(str,i)) for i in Counter(x).items()]))
339 ms ± 51 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
答案 1 :(得分:1)
也许在collections.Counter
参数中使用apply
,并且还使用双''.join
来从dict
ionion生成字符串:
from collections import Counter
df['Code']=df['Code'].apply(lambda x: ''.join([''.join(map(str,i)) for i in Counter(x).items()]))
现在:
print(df)
是:
Name Code
0 Cedric A1M4
1 Joe A1
2 Mickael A1M2C1X1
3 Dupond M7
答案 2 :(得分:1)
计数必须考虑不连续的重复项。
首先是一个编码代码的函数:
def encode(code):
cpt=1
n=len(code)
res=''
for i in range(n):
if i == n-1 or code[i] != code[i+1]:
res += str(cpt)+code[i]
cpt=1
else: cpt+=1
return res
示例:scan('AABBCA')
-> '2A2B1C1A'
。
然后只需将df['Code']=df.Code.apply(encode)
应用于:
Name Code
0 Cedric 1A4M
1 Joe 1A
2 Mickael 1A2M1C1X
3 Dupond 7M
4 Jean 1A3M1C1M1C
答案 3 :(得分:0)
您可以使用Counter from collections
来计算出现次数。稍后,您可以join
键和值对。此外,您可以应用pandas DataFrame的df.apply
功能
from collections import Counter as ctr
df['Code'] = df['Code'].apply(lambda x: ''.join([''.join(map(str, val[::-1])) for val in ctr(x).items()]))
我在这里使用val[::-1]
,因此输出将与您的期望一样。
Name Code
0 Cedric 1A4M
1 Joe 1A
2 Mickael 1A1X1C2M
3 Dupond 7M
答案 4 :(得分:0)
谢谢,
这里是两种方法的比较:
from itertools import groupby
%timeit df['Code'] = [''.join(f"{len(''.join(group))}{key}" for key, group in groupby(x)) for x in df['Code']]
CPU times: user 511 µs, sys: 7 µs, total: 518 µs
Wall time: 524 µs
和
def encode(code):
cpt=1
n=len(code)
res=''
for i in range(n):
if i == n-1 or code[i] != code[i+1]:
res += str(cpt)+code[i]
cpt=1
else: cpt+=1
return res
%timeit result['CDSCENARIO']=result.CDSCENARIO.apply(encode)
CPU times: user 855 µs, sys: 10 µs, total: 865 µs
Wall time: 871 µs
第一种方法比第二种方法快。