Python-Pandas-计算字符串中出现的字符数并替换字符串值

时间:2018-12-04 07:55:50

标签: python python-3.x pandas dataframe

已编辑:

我有以下数据框

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万行的巨大数据框。当我执行此代码时,该过程太长了。

我正在寻找一种更好的解决方案。

已编辑:我在数据框中添加了最后一个示例。先前的响应无法处理此示例。我想处理这个用例

感谢您的帮助。

5 个答案:

答案 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

第一种方法比第二种方法快。