如何使用 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
酷,似乎replace
比findall
花费的时间是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 从字符串中提取算术运算的主要内容,如果未能解决你的问题,请参考以下文章
如何从python中的pandas数据框中的列中提取关键字(字符串)