根据单词是不是大写拆分熊猫数据框列

Posted

技术标签:

【中文标题】根据单词是不是大写拆分熊猫数据框列【英文标题】:Splitting a pandas Data frame column depending if word is capital or not根据单词是否大写拆分熊猫数据框列 【发布时间】:2022-01-17 13:53:51 【问题描述】:

我有以下格式的数据框列:

header
THIS IS an example
ALSO this
ONE LAST
J. one more

我想把它分成两列:

header1 header2
THIS IS an example
ALSO this
ONE LAST null
null J. one more

我尝试过这样提取信息:

df1['header'].str.split('[A-Z]', expand=True)

但我的正则表达式达不到标准。非常感谢任何帮助!

【问题讨论】:

【参考方案1】:

希腊字母通知

要仅匹配希腊大写字母,请将以下模式中的 [A-Z] 替换为 [\u0391-\u03A1\u03A3-\u03A9]。要匹配 ASCII 和希腊大写字母,请使用 [a-zA-Z\u0391-\u03A1\u03A3-\u03A9]

rx = r'^\s*(?P<header1>(?:[\u0391-\u03A1\u03A3-\u03A9]+\b(?!\.)(?:\s+[\u0391-\u03A1\u03A3-\u03A9]+)*\b)?)(?:\s+(?P<header2>.*))?'
new_df = df['header'].str.extract(rx, expand=True)

见the regex demo。

你可以使用

df[['header1', 'header2']] = df['header'].str.extract(r'^\s*((?:[A-Z]+\b(?!\.)(?:\s+[A-Z]+)*)?)\s*(.*)', expand=True)

输出:

>>> df
               header   header1      header2
0  THIS IS an example   THIS IS   an example
1           ALSO this      ALSO         this
2            ONE LAST  ONE LAST             
3         J. one more            J. one more           

请参阅regex demo。

详情

^ - 字符串开头 \s* - 零个或多个空格 ((?:[A-Z]+\b(?!\.)(?:\s+[A-Z]+)*)?) - 第 1 组 (header1):一个或多个大写 ASCII 字母的可选序列(不跟 . 字符),然后是零个或多个一个或多个空格和一个或多个大写 ASCII 字母的序列 \s* - 零个或多个空格 (.*) - 第 2 组 (header2):除换行符之外的任何零个或多个字符,尽可能多。

您可以使用命名捕获组提取到新的数据帧:

>>> new_df = df['header'].str.extract(r'^\s*(?P<header1>(?:[A-Z]+\b(?!\.)(?:\s+[A-Z]+)*)?)\s*(?P<header2>.*)', expand=True)
>>> new_df
    header1      header2
0   THIS IS   an example
1      ALSO         this
2  ONE LAST             
3            J. one more

【讨论】:

当我运行您的示例时,它运行良好,但在我的数据框中却没有,尽管我涵盖了所有情况。它返回两个空列。可能是因为编码?我的数据集是 utf8,你提到了 ascii。还是我应该在其他地方寻找问题的根源?再次感谢您的帮助。 @PeterGould [A-Z] 仅匹配 ASCII 大写字母。例如,它与Ф 不匹配。使用 ASCII 或 UTF8 对文件进行编码并不重要,这与此无关。如果您得到空列,则表示您没有与我们共享您拥有的数据。我们只能测试您分享的内容。 @PeterGould Here,你显示希腊大写字母。你需要支持希腊语吗? @PeterGould 我在答案的顶部添加了一条注释。 @PeterGould 使用r'^\s*(?P&lt;header1&gt;(?:[\u0391-\u03A1\u03A3-\u03A9]+\b(?!\.)(?:\s+[\u0391-\u03A1\u03A3-\u03A9]+)*\b)?)(?:\s+(?P&lt;header2&gt;.*))?'【参考方案2】:

您还可以使用 2 个命名捕获组,并加入列。

^(?P<header1>[A-Z]+(?:[^\S\n]+[A-Z]+)*)?(?:(?:^|[^\S\n]+)(?P<header2>.+))?$

(如果必须以小写字符开头,则使用[a-z].* 而不是.+

^ 字符串开始 (?P&lt;header1&gt;[A-Z]+捕获组header1,匹配1+ chars A-Z (?:[^\S\n]+[A-Z]+)*)? 可选匹配空格和 1+ 字符 A-Z (?:非捕获组 (?:^|[^\S\n]+) 断言字符串的开头或匹配 1+ 个空格 (?P&lt;header2&gt;.+) 命名组 header2 匹配 1+ 个字符 )? 关闭群组并将其设为可选 $ 字符串结束

查看regex demo 和Python demo。

例子

import pandas as pd

strings = [
    "THIS IS an example",
    "ALSO this",
    "ONE LAST",
    "J. one more"
]
df1 = pd.DataFrame(strings, columns=["header"])
df1 = df1.join(
    df1['header'].str.extract(
        '^(?P<header1>[A-Z]+(?:[^\S\n]+[A-Z]+)*)?(?:(?:^|[^\S\n]+)(?P<header2>.+))?$',
        expand=True
    )
    .fillna('')
)

print(df1)

输出

               header   header1      header2
0  THIS IS an example   THIS IS   an example
1           ALSO this      ALSO         this
2            ONE LAST  ONE LAST             
3         J. one more            J. one more

       

【讨论】:

我在这里收到以下错误ValueError: columns overlap but no suffix specified: Index(['area_lvl_2', 'area_lvl_1'], dtype='object') @PeterGould 我无法重现,我得到了这个输出ideone.com/Jqptim你使用相同的列名吗? 是的,我更改了列名,现在它正在运行。但不填充列 header1 和 header2。这就是我得到的 |header|header1|header2| |--------|------------|----------| |ΓΙΑΝΝΙΤΣΩΝ |null |null| |ΕΛΕΥΘΕΡΙΟ Άγιος Γεώργιος|空 |空| |ΕΛΕΥΘΕΡΙΟ |null |null| |ΕΛΕΥΘΕΡΙΟ |null |null| @PeterGould 你已经更新了这个问题,为此我已经更新了我的答案。我添加了一个示例来说明对于给定的数据它是有效的。我无法从您的 cmets 重现结果。你可以做的是用不适合你的代码更新问题,这样你就可以在代码工作的地方得到答案。【参考方案3】:

使用str.extract我们可以试试:

df["header1"] = df["header"].str.extract(r'^([A-Z]+(?: [A-Z]+)?)')
df["header2"] = df["header"].str.extract(r'\b([a-z]+(?: [a-z]+)?)')

【讨论】:

以上是关于根据单词是不是大写拆分熊猫数据框列的主要内容,如果未能解决你的问题,请参考以下文章

将熊猫数据框列列表值拆分为重复行[重复]

熊猫数据框列上的子字符串

熊猫将数据框列写入 csv

如何从熊猫数据框列中选择日期间隔? [复制]

熊猫:将列中的列表拆分为多行[重复]

用另一个值替换熊猫数据框列中的几个值