您可以使用 .str.split() 一步捕获 Panda 数据框列中的多个子字符串吗

can you capture multiple substrings in a Panda dataframe column using .str.split() in one step

我有一个数据库,在 Pandas 数据框中有一列,其中包含一个字符串,该字符串具有我提取的两个子字符串(一个字符串和一个数字)。我用 str.split() 来做,但不是以一种非常 pythonic 的方式,因为至少对我来说,拆分 returns 拆分到数据库的第一个项目。我当然可以将结果分配给一个单独的数据框来完成拆分并将其带回来。

我相信有更好的方法来做到这一点,但到目前为止我还没有找到它。

这是一个说明性数据框:

df = pd.DataFrame ({'d': {71: '2022-01-03', 72: '2022-01-04', 73: '2022-01-06', 74: '2022-01-07', 75: '2022-01-07'},
                    'e': {71: 'MDU(US5526901096) Cash Dividend USD 0.2175 per Share (Ordinary Dividend)',
                          72: 'KMB(US4943681035) Cash Dividend USD 1.14 per Share (Ordinary Dividend)',
                          73: 'IRM(US46284V1017) Cash Dividend USD 0.6185 per Share (Ordinary Dividend)',
                          74: 'MRK(US58933Y1055) Cash Dividend USD 0.69 per Share (Ordinary Dividend)',
                          75: 'PEP(US7134481081) Cash Dividend USD 1.075 per Share (Ordinary Dividend)'}, 
                    'f': {71: '108.75', 72: '1368', 73: '556.65', 74: '345', 75: '537.5'}})
df

基本上,我想从这个数据框中提取股票代码和股息金额,而不会丢失 'd' 和 'f' 的其他列。

从 'e' 列的字符串中,我在字符串的开头提取股票代码,然后从中间提取当前股息。

df_to_process['e'] = df_to_process['e'].str.split('\(', expand=True) 为我提供了股票代码。

为了获得股息金额,我将数据框中的列 'e' 数据复制到我创建的列中,出于此处的目的 'gg'。然后我把它分开了。由于股息金额在我的拆分中间,所以我创建的列得到了我想要的数字。

df_to_process[['aa','gg','cc']]  = df_to_process['gg'].str.split('USD|per', expand=True)
or
y = df['gg'].str.split('USD|per', expand=True)

            0                   1                    2
71  MDU(US5526901096) Cash Dividend 0.2175  Share (Ordinary Dividend)
72  KMB(US4943681035) Cash Dividend 1.14    Share (Ordinary Dividend)
73  IRM(US46284V1017) Cash Dividend 0.6185  Share (Ordinary Dividend)
74  MRK(US58933Y1055) Cash Dividend 0.69    Share (Ordinary Dividend)
75  PEP(US7134481081) Cash Dividend 1.075   Share (Ordinary Dividend)

我对 Regex 不是很熟悉,接下来将转向它。但是有没有办法使它与拆分一起工作?

这没有以任何方式进行优化,它做了一些假设,但我试图在下面突出显示它们。

import pandas as pd
import re

def parse_row(row) :
  match = re.search('^([a-zA-Z]+).*USD (\d+\.?\d*) per', row, re.I)
  return pd.Series([match.group(1), match.group(2)])

df[['symbol', 'qrtrly_div_total']] = df['e'].apply( parse_row )

>>> df
             d                                                  e       f symbol qrtrly_div_total
71  2022-01-03  MDU(US5526901096) Cash Dividend USD 0.2175 per...  108.75    MDU           0.2175
72  2022-01-04  KMB(US4943681035) Cash Dividend USD 1.14 per S...    1368    KMB             1.14
73  2022-01-06  IRM(US46284V1017) Cash Dividend USD 0.6185 per...  556.65    IRM           0.6185
74  2022-01-07  MRK(US58933Y1055) Cash Dividend USD 0.69 per S...     345    MRK             0.69
75  2022-01-07  PEP(US7134481081) Cash Dividend USD 1.075 per ...   537.5    PEP            1.075

如您所述,regex 允许您捕获这两个元素并将它们分配给新列。 python3 doc for regex

如果E列不一致,你需要修改正则表达式,但这里是上面的元素。

'^([a-zA-Z]+).*USD (\d+\.?\d*) per'

^表示从头开始

[a-zA-Z]+ 将检查开头的所有字母,直到不满足字母为止(假设库存中至少有 1 个字母长度,当遇到 (

.*USD 匹配所有内容,直到我们到达 USD

\d+.?\d* 应该匹配一个数字,有或没有小数点,如果有小数点,那么它后面的所有数字

per 最后是为了帮助隔离“USD xx.xx per”

之间的数字匹配

如果需要优化,例如对于大型数据集,pd.apply 不是理想的使用函数,我建议研究矢量化技术。

编辑:如果您想为匹配项命名,可以这样做。

match = re.search('^(?P<symbol>[a-zA-Z]+).*USD (?P<value>\d+\.?\d*) per', row, re.I) 
match.group('symbol') 
match.group('value')

(?P<name>...) 允许您为群组命名。