如何使用 Pandas 从字符串中提取算术运算

Posted

技术标签:

【中文标题】如何使用 Pandas 从字符串中提取算术运算【英文标题】:How to extract an arithmetic operation from a string with Pandas 【发布时间】:2020-09-30 21:24:50 【问题描述】:

在 Pandas 数据帧中

>> df.head()

    A                               B             C
0   1    â#0.00 + "s=?0.07 + 'due0.93    rt@-[ 3.01
1   2    â#0.02 + "s=?0.16 + 'due0.82    rt@-[ 2.97
...

我想只提取数值。专栏C我可以用,例如,

>> extr = df['C'].str.extract(r'(\d+\.\d+)', expand=False)
>> df['C'] = pd.to_numeric(extr)
>> df.head()

    A                               B       C
0   1    â#0.00 + "s=?0.07 + 'due0.93    3.01
1   2    â#0.02 + "s=?0.16 + 'due0.82    2.97
...

B 列有问题。如何提取 + 操作以及浮点数?我试过了

>> extr = df['B'].str.extract(r'(\d+\.\d+)\+(\d+\.\d+)\+(\d+\.\d+)', expand=False)

我希望能给我类似的东西

                    0
0    '0.00+0.07+0.93'
1    '0.02+0.16+0.82'
...

但它给了我三列,其中包含NaN 值:

       0      1      2
0    NaN    NaN    NaN
1    NaN    NaN    NaN
...

那么我怎样才能提取整个算术运算呢?

(只需要+操作,其他字符如-可以忽略。)

【问题讨论】:

【参考方案1】:

一种方法是在提取的数据上运行str join,使用+作为分隔符

import re

df = pd.read_clipboard(sep='\s2,')


df['extract'] = ["+".join(re.findall("(\d+\.?\d+)",entry)) for entry in df.B]


    A                 B                  C         extract
0   1   â#0.00 + "s=?0.07 + 'due0.93    3.01    0.00+0.07+0.93
1   2   â#0.02 + "s=?0.16 + 'due0.82    2.97    0.02+0.16+0.82

【讨论】:

【参考方案2】:

Python 不是我的强项,但我会改用replace 并对两列进行操作,也许看看:

df[['B', 'C']] = df[['B','C']].replace(r'[^\d.+]', '', regex=True)
print(df)

结果:

   A               B     C
0  1  0.00+0.07+0.93  3.01
1  2  0.02+0.16+0.82  2.97

如果它只是 B 列,那么您可能只是使用:

extr = df['B'].str.replace(r'[^\d.+]', '')

【讨论】:

【参考方案3】:

另一种使用Series.str.findall的方法:

df['B'] = df['B'].str.findall(r'(\d+(?:.\d+)?)').agg('+'.join)

# print(df)
   A               B     C
0  1  0.00+0.07+0.93  3.01
1  2  0.02+0.16+0.82  2.97

timeit所有解决方案的比较:

df.shape
(20000, 4)

%%timeit -n100 @Shubham solution
df['B'].str.findall(r'(\d+(?:.\d+)?)').agg('+'.join)
31.9 ms ± 1.51 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)


%%timeit -n100 @Rakesh solution
df["B"].str.findall(r"(\d+\.\d+)").str.join("+")
32.7 ms ± 1.71 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)


%%timeit -n100 @Sammy solution
["+".join(re.findall("(\d+\.?\d+)",entry)) for entry in df.B]
36.8 ms ± 431 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


%%timeit -n100 @JudV solution
df['B'].str.replace(r'[^\d.+]', '')
59.7 ms ± 5.81 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

【讨论】:

@Judv 我想应该没有任何区别,但我会运行timeit 以确保并让您知道结果。 @Judv 得到了timeit 结果,猜猜它们在性能方面几乎相同。 @JudV 一栏B 酷,似乎replacefindall 花费的时间是findall 的两倍。太糟糕了 这让我认为 Pandas 中的字符串处理比 vanilla python 慢。至少对于这个用例来说——爱因斯坦的概括是存在的!【参考方案4】:

这是使用str.findall.str.join("+") 的一种方法

例如:

df = pd.DataFrame("B": ["""â#0.00 + "s=?0.07 + 'due0.93""", """â#0.02 + "s=?0.16 + 'due0.82"""])
df["Z"] = df["B"].str.findall(r"(\d+\.\d+)").str.join("+")

print(df)

输出:

                              B               Z
0  â#0.00 + "s=?0.07 + 'due0.93  0.00+0.07+0.93
1  â#0.02 + "s=?0.16 + 'due0.82  0.02+0.16+0.82

【讨论】:

以上是关于如何使用 Pandas 从字符串中提取算术运算的主要内容,如果未能解决你的问题,请参考以下文章

R因子的算术运算

如何从python中的pandas数据框中的列中提取关键字(字符串)

如何对char类型进行安全算术运算

Pandas基本功能之算术运算排序和排名

如何从 Python Pandas Dataframe 中的 STRING 列中提取嵌套字典?

使用 pandas [Python] 提取 xls 文件后如何从输出中删除编号