给出下表:

df = pd.DataFrame({'code':['100M','60M10N40M','5S99M','1S25I100M','1D1S1I200M']})

这看起来是这样的:

    code
0   100M
1   60M10N40M
2   5S99M
3   1S25I100M
4   1D1S1I200M

我想将code列字符串转换为数字,其中M、N、D分别等于(乘1),I等于(乘-1),S等于(乘0).

结果应该如下所示:

     code       Val
0   100M        100     This is (100*1)
1   60M10N40M   110     This is (60*1)+(10*1)+(40*1)
2   5S99M       99      This is (5*0)+(99*1)
3   1S25I100M   75      This is (1*0)+(25*-1)+(100*1)
4   1D1S1I200M  200     This is (1*1)+(1*0)+(1*-1)+(200*1)

我为此编写了以下函数:

def String2Val(String):
    # Generate substrings
    sstrings = re.findall('.[^A-Z]*.', String)

    KeyDict = {'M':'*1','N':'*1','I':'*-1','S':'*0','D':'*1'}

    newlist = []
    for key, value in KeyDict.items():
        for i in sstrings:
            if key in i:
                p = i.replace(key, value)
                lp = eval(p)
                newlist.append(lp)

    OutputVal = sum(newlist)
    return OutputVal

df['Val'] = df.apply(lambda row: String2Val(row['code']), axis = 1)

在将该函数应用于表之后,我意识到当应用于大型数据集时,它的效率很低,而且耗时很长.我如何才能优化这个过程?

推荐答案

由于PANDA字符串方法没有经过优化(尽管对于PANAAS 2.0似乎不再是这样),如果您追求的是性能,最好在循环中使用Python字符串方法(用C编译).似乎每个字符串上的简单循环可能会提供最佳性能.

def evaluater(s):
    total, curr = 0, ''
    for e in s:
        # if a number concatenate to the previous number
        if e.isdigit():
            curr += e
        # if a string, look up its value in KeyDict
        # and multiply the currently collected number by it
        # and add to the total
        else:
            total += int(curr) * KeyDict[e]
            curr = ''
    return total

KeyDict = {'M': 1, 'N': 1, 'I': -1, 'S': 0, 'D': 1}
df['val'] = df['code'].map(evaluater)

执行情况:

KeyDict1 = {'M':'*1+','N':'*1+','I':'*-1+','S':'*0+','D':'*1+'}
df = pd.DataFrame({'code':['100M','60M10N40M','5S99M','1S25I100M','1D1S1I200M']*1000})

%timeit df.assign(val=df['code'].map(evaluater))
# 12.2 ms ± 579 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df.assign(val=df['code'].apply(String2Val))    # @Marcelo Paco
# 61.8 ms ± 2.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit df.assign(val=df['code'].replace(KeyDict1, regex=True).str.rstrip('+').apply(pd.eval))   # @Ynjxsjmh
# 4.86 s ± 155 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

注:您已经实现了类似的东西,但是外部循环(for key, value in KeyDict.items())是不必要的;因为KeyDict是一个字典,所以将其用作查找表;不要循环.此外,当只有一列相关时,.apply(axis=1)也不是一种非常糟糕的循环方式. Select 该列并拨打apply().

Python相关问答推荐

Python中MongoDB的BSON时间戳

Pandas 有条件轮班操作

如何记录脚本输出

修复mypy错误-赋值中的类型不兼容(表达式具有类型xxx,变量具有类型yyy)

Python虚拟环境的轻量级使用

如何在python polars中停止otherate(),当使用when()表达式时?

如何使Matplotlib标题以图形为中心,而图例框则以图形为中心

Pandas Loc Select 到NaN和值列表

如何在TensorFlow中分类多个类

(Python/Pandas)基于列中非缺失值的子集DataFrame

Numpyro AR(1)均值切换模型抽样不一致性

处理Gekko的非最优解

如何在Python中使用Iscolc迭代器实现观察者模式?

递归函数修饰器

使用python playwright从 Select 子菜单中 Select 值

在第一次调用时使用不同行为的re. sub的最佳方式

Django在一个不是ForeignKey的字段上加入'

有了Gekko,可以创建子模型或将模型合并在一起吗?

如何在表单中添加管理员风格的输入(PDF)

两个名称相同但值不同的 Select 都会产生相同的值(discord.py)