Pandas使用教程 - 字符串操作高级技巧 (extract, findall)

进阶篇37. 字符串操作高级技巧 (extract, findall)

在数据清洗和文本处理任务中,字符串操作起着至关重要的作用。对于复杂文本数据,我们往往需要利用正则表达式从字符串中提取关键信息,或查找所有匹配模式的子串。Pandas 中的 str.extract()str.findall() 方法提供了强大而灵活的工具,帮助我们完成这些任务。

本文将详细介绍这两个方法的基本原理、数学表达、代码示例和实际应用场景,帮助你在数据预处理和特征工程中更高效地处理文本数据。


1. str.extract() 方法

1.1 基本概念

str.extract() 用于从字符串中提取符合正则表达式捕获组的部分。其基本思想是:给定一个正则表达式模式,通过括号定义的捕获组来选取字符串中的目标子串。数学上,设字符串 ( s ) 中存在某个子串满足正则表达式 ( R ),则
extract ( s , R ) = x 其中  x  是  s  中匹配捕获组的子串 \text{extract}(s, R) = x \quad \text{其中 } x \text{ 是 } s \text{ 中匹配捕获组的子串} extract(s,R)=x其中 x  s 中匹配捕获组的子串

如果正则表达式有多个捕获组,extract() 会返回一个 DataFrame,每个捕获组对应一列。

1.2 示例代码

假设我们有一列包含混合文本的 Series,其中包含日期和时间信息,我们希望提取出日期部分:

import pandas as pd

# 示例数据:包含日期和其他信息的字符串
s = pd.Series([
    "Order placed on 2024-01-15 at 14:30",
    "Delivery scheduled for 2024-02-20, please confirm",
    "No date available",
    "Invoice date: 2024-03-05"
])

# 使用正则表达式提取日期(格式:YYYY-MM-DD)
# 正则表达式解释:(\d{4}-\d{2}-\d{2}) 捕获4位数字-2位数字-2位数字的日期格式
dates_extracted = s.str.extract(r"(\d{4}-\d{2}-\d{2})")
print("提取出的日期:")
print(dates_extracted)

输出结果为:

             0
0  2024-01-15
1  2024-02-20
2         NaN
3  2024-03-05

在此示例中,str.extract() 根据正则表达式捕获了字符串中的日期信息,对于不匹配的文本则返回 NaN。

1.3 多捕获组示例

如果正则表达式中包含多个捕获组,extract() 会返回一个 DataFrame,包含每个捕获组的结果。如下例所示,我们同时提取日期和时间信息:

# 示例数据:同时包含日期和时间的字符串
s2 = pd.Series([
    "Order placed on 2024-01-15 at 14:30",
    "Delivery scheduled for 2024-02-20 at 09:45",
    "Invoice date: 2024-03-05, time: 16:20"
])

# 正则表达式:第一个捕获组提取日期,第二个捕获组提取时间(格式:HH:MM)
pattern = r"(\d{4}-\d{2}-\d{2}).*?(\d{2}:\d{2})"
extracted = s2.str.extract(pattern)
print("提取出的日期和时间:")
print(extracted)

输出结果为:

             0      1
0  2024-01-15  14:30
1  2024-02-20  09:45
2  2024-03-05  16:20

2. str.findall() 方法

2.1 基本概念

str.findall() 方法用于查找字符串中所有匹配正则表达式的子串,并返回一个列表。数学上,对于一个字符串 ( s ) 和正则表达式 ( R ),该方法生成一个列表:
findall ( s , R ) = [ x 1 , x 2 , … , x k ] \text{findall}(s, R) = [x_1, x_2, \dots, x_k] findall(s,R)=[x1,x2,,xk]
其中每个 ( x_i ) 是 ( s ) 中匹配 ( R ) 的一个子串。

2.2 示例代码

假设我们有一个文本,想要提取其中所有的数字序列:

import pandas as pd

# 示例数据:包含多个数字的字符串
s = pd.Series([
    "The price is 100 dollars, and the discount is 20%",
    "Order 1234: quantity 10, unit price 15.5",
    "No numbers here",
    "Call 555-1234 or 555-5678 for support"
])

# 使用正则表达式提取所有数字
# \d+ 匹配一个或多个数字
numbers = s.str.findall(r"\d+")
print("提取出的所有数字:")
print(numbers)

输出结果可能为:

0       [100, 20]
1    [1234, 10, 15, 5]
2                []
3      [555, 1234, 555, 5678]
dtype: object

注意:在第二行中,“15.5” 被分解成 [15, 5],因为正则表达式 \d+ 不匹配小数点。如果需要匹配带小数点的数字,可以修改正则表达式。

2.3 匹配复杂模式

假设我们希望提取电子邮件地址,findall() 方法也可以用于这种情况:

s_emails = pd.Series([
    "Please contact us at support@example.com for assistance.",
    "Send feedback to feedback@domain.org and sales@domain.org.",
    "No email provided."
])

emails = s_emails.str.findall(r"[\w\.-]+@[\w\.-]+\.\w+")
print("提取出的电子邮件地址:")
print(emails)

输出结果为:

0          [support@example.com]
1    [feedback@domain.org, sales@domain.org]
2                            []
dtype: object

3. 应用场景与最佳实践

3.1 应用场景

  • 数据清洗:利用 extract 和 findall 可以从混合文本中提取有用信息,如日期、时间、价格、电子邮件地址等。
  • 特征工程:在机器学习中,提取文本中的关键信息并转换为结构化特征有助于提高模型性能。
  • 文本分析:在自然语言处理任务中,可以用 findall 获取文本中所有符合特定模式的词或短语,进行频率统计和情感分析。

3.2 最佳实践

  • 使用原始字符串:编写正则表达式时,推荐使用原始字符串(例如,r"\d+")以避免转义问题。
  • 逐步测试正则表达式:在对整个 Series 应用 extract 或 findall 前,先在单个字符串上测试正则表达式,确保其正确匹配目标模式。
  • 捕获组的设计:合理设计捕获组,确保 extract 返回所需的结果;如果只需要单个值,确保正则表达式中只有一个捕获组。
  • 处理缺失与空列表:对于没有匹配到的字符串,extract 返回 NaN,而 findall 返回空列表,根据后续需求进行处理,如填充默认值。

4. 综合案例:用户评论中的关键信息提取

假设我们有一份用户评论数据,其中包含电子邮件、电话号码和日期信息。我们希望同时提取出这些信息进行进一步分析。

import pandas as pd

data = {
    'Comment': [
        "Contact us at support@example.com on 2024-01-15.",
        "Email feedback to feedback@domain.org; call 555-1234.",
        "Meeting scheduled for 2024-02-20. No email provided.",
        "Send inquiry to info@service.cn or call 010-88886666 on 2024-03-05."
    ]
}
df = pd.DataFrame(data)

# 提取电子邮件地址
df['Email'] = df['Comment'].str.extract(r"([\w\.-]+@[\w\.-]+\.\w+)", expand=False)

# 提取日期(格式 YYYY-MM-DD)
df['Date'] = df['Comment'].str.extract(r"(\d{4}-\d{2}-\d{2})", expand=False)

# 提取电话号码(简单模式:匹配包含数字、连字符和括号)
df['Phone'] = df['Comment'].str.findall(r"[\d\-\(\)]+")
print("提取后的数据:")
print(df)

输出结果示例:

                                            Comment                 Email        Date             Phone
0         Contact us at support@example.com on 2024-01-15.  support@example.com  2024-01-15         [2024-01-15]
1        Email feedback to feedback@domain.org; call 555-1234.  feedback@domain.org        NaN        [555-1234]
2         Meeting scheduled for 2024-02-20. No email provided.                   NaN  2024-02-20               []
3  Send inquiry to info@service.cn or call 010-88886666 on 2024-03-05.     info@service.cn  2024-03-05  [010-88886666]

在这个案例中,我们分别使用 extract()findall() 方法提取评论中的电子邮件和日期(单值,使用 extract)以及电话号码(可能有多个,使用 findall)。


5. 总结

本文详细介绍了 Pandas 中字符串操作的高级技巧,重点讨论了 str.extract()str.findall() 的应用。主要内容包括:

  • str.extract()

    • 利用正则表达式捕获组从字符串中提取关键信息,返回一个 DataFrame 或 Series。
    • 适用于提取单个匹配值,如日期、电子邮件等。
  • str.findall()

    • 查找字符串中所有匹配正则表达式的子串,并以列表形式返回。
    • 适用于可能存在多个匹配项的场景,如提取所有电话号码、关键词等。

通过多个示例,我们展示了如何在实际数据清洗、特征工程和文本分析中灵活应用这些方法。掌握这些高级技巧,可以帮助你高效地从非结构化文本数据中提取有价值的信息,并为后续的数据分析和模型构建提供结构化特征。


6. 参考资料

  • Pandas 官方文档:Series.str.extract
  • Pandas 官方文档:Series.str.findall
  • 《Python for Data Analysis》 by Wes McKinney
  • 相关博客文章,如 优快云 和知乎上关于“Pandas 正则表达式高级技巧”的讨论

希望本文能帮助你深入理解并灵活运用 Pandas 中的 extract 与 findall 方法,在数据清洗和文本分析中提取出有用信息,不断实践与探索,将使你在数据科学领域取得更高效、更精确的结果。

### 如何用 Pandas 提取 DataFrame 某列字符串中的数字 在 Pandas 中,可以通过多种方法实现从某列字符串中提取数字的功能。以下是几种常见的解决方案: #### 方法一:使用 `str.extract` 和正则表达式 Pandas 的 `.str.extract()` 函数允许通过正则表达式从字符串中提取子串。如果目标是从某一列中提取所有的数字,则可以利用正则表达式 `\d+` 来匹配连续的数字。 ```python import pandas as pd # 创建示例 DataFrame df = pd.DataFrame({'col': ['abc123', 'def456', 'ghi789']}) # 使用 str.extract 提取数字 df['extracted_numbers'] = df['col'].str.extract(r'(\d+)') print(df) ``` 上述代码会创建一个新的列 `extracted_numbers`,该列包含原列中提取到的第一个数字序列[^1]。 #### 方法二:使用 `str.findall` 当需要提取多个数字时,`.str.findall()` 是更合适的选择。此方法返回的是列表形式的结果,适用于每条记录可能有多个数字的情况。 ```python # 修改示例数据以便展示 findall 功能 df = pd.DataFrame({'col': ['abc123xyz456', 'def456', 'ghi789jkl012']}) # 使用 str.findall 查找所有数字 df['found_all_numbers'] = df['col'].str.findall(r'\d+').apply(','.join) print(df) ``` 这里将找到的所有数字连接成逗号分隔的形式存入新列中[^4]。 #### 方法三:自定义函数配合 `apply` 对于更加复杂的模式或者条件下的数值提取需求,也可以编写自己的 Python 函数并通过 `apply` 应用于整个 Series 或者 DataFrame 列上。 ```python # 自定义一个简单的提取数字函数 def extract_digits(s): import re match = re.search(r'\d+', s) return match.group(0) if match else None # 将函数应用至整列 df['custom_extracted'] = df['col'].apply(extract_digits) print(df) ``` 这种方法灵活性更高,适合于那些无法单纯依靠正则表达式的场景[^3]。 --- ### 总结 以上介绍了三种不同的方式来完成从 Pandas DataFrame 字符串列中提取数字的任务。具体采用哪种取决于实际应用场景以及数据特点。无论是简单还是复杂的需求,都可以借助 Pandas 强大的字符串操作功能轻松解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲人编程

你的鼓励就是我最大的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值