本文详细介绍了如何在Pandas DataFrame中处理包含不规则字符串和数字的列。通过利用pandas.Series.str.extract结合正则表达式,可以高效地从混合文本中提取数值,并将其转换为可计算的整数类型。教程还进一步演示了如何对提取出的数据进行分组求和,并提供了根据特定条件进行聚合的高级技巧,旨在帮助用户精确地清洗和分析非结构化数据。
问题场景:从混合文本中提取数值
在实际数据处理中,我们经常会遇到某一列数据中包含混合类型信息的情况,例如数字和文本混杂在一起,且格式不统一。一个典型的例子是销售数据,其中销售数量可能被描述为“1 table”、“3chairs”或“8 cushions”,数字与单位紧密相连,且单位词汇不固定。为了对这些销售数量进行统计分析(如按类别求和),我们首先需要将这些数字从字符串中精确地提取出来。
假设我们有以下Pandas DataFrame:
import pandas as pd import io data = """Category Sales Paid Table 1 table Yes Chair 3chairs Yes Cushion 8 cushions Yes Table 3Tables Yes Chair 12 Chairs No Mats 12Mats Yes """ df = pd.read_csv(io.StringIO(data), sep=r's+') print(df)
输出:
Category Sales Paid 0 Table 1 table Yes 1 Chair 3chairs Yes 2 Cushion 8 cushions Yes 3 Table 3Tables Yes 4 Chair 12 Chairs No 5 Mats 12Mats Yes
我们的目标是从Sales列中提取纯数字,并按Category列进行分组求和。
解决方案:使用str.extract和正则表达式
Pandas提供了一个强大的字符串处理方法str.extract,它允许我们使用正则表达式从字符串中提取匹配的模式。
1. 提取数值
首先,我们需要定义一个正则表达式来匹配字符串开头的数字。正则表达式^(d+)的含义如下:
- ^:匹配字符串的开头。
- d+:匹配一个或多个数字(0-9)。
- ():捕获组,表示我们想要提取这部分匹配到的内容。
我们将这个正则表达式应用于Sales列,并设置expand=False,这样str.extract会返回一个Series而不是DataFrame。
# 提取Sales列开头的数字 extracted_numbers = df['Sales'].str.extract('^(d+)', expand=False) print("提取出的原始数字字符串:") print(extracted_numbers)
输出:
提取出的原始数字字符串: 0 1 1 3 2 8 3 3 4 12 5 12 Name: Sales, dtype: object
此时,提取出的数字仍然是字符串类型(dtype: object)。为了进行数学运算,我们需要将其转换为整数类型。
2. 类型转换
使用astype(int)将提取出的字符串数字转换为整数:
# 转换为整数类型 numeric_sales = extracted_numbers.astype(int) print("n转换为整数后的数字:") print(numeric_sales)
输出:
转换为整数后的数字: 0 1 1 3 2 8 3 3 4 12 5 12 Name: Sales, dtype: int64
3. 分组求和
现在我们有了纯数字的numeric_sales Series,可以结合原始DataFrame的Category列进行分组求和了。
# 按Category分组求和 total_sales_per_category = numeric_sales.groupby(df['Category']).sum() print("n按类别汇总的总销售额:") print(total_sales_per_category)
输出:
按类别汇总的总销售额: Category Chair 15 Cushion 8 Mats 12 Table 4 Name: Sales, dtype: int64
高级应用:条件性分组求和
有时,我们可能需要根据额外的条件进行聚合,例如只计算“Paid”状态为“Yes”的销售额。在这种情况下,我们可以在提取数字之前先对数据进行筛选或条件性处理。
Pandas的where方法非常适合这种场景。它根据条件选择Series中的元素,不满足条件的元素会被替换为指定的值(默认为NaN)。在这里,我们将不满足“Paid”为“Yes”的Sales值替换为字符串“0”,这样在后续提取和转换时,这些项会变成数字0,而不会影响总和。
# 只计算Paid为'Yes'的销售额 paid_sales_only = df['Sales'].where(df['Paid'] == 'Yes', other='0') # 对处理后的列再次提取数字并转换为整数 numeric_paid_sales = paid_sales_only.str.extract('^(d+)', expand=False).astype(int) # 按Category分组求和 paid_sales_per_category = numeric_paid_sales.groupby(df['Category']).sum() print("n按类别汇总的已支付销售额:") print(paid_sales_per_category)
输出:
按类别汇总的已支付销售额: Category Chair 3 Cushion 8 Mats 12 Table 4 Name: Sales, dtype: int64
通过where(df[‘Paid’] == ‘Yes’, other=’0′)这一步,当Paid列不是’Yes’时,对应的Sales值(例如12 Chairs)会被替换为’0’。这样,在后续的str.extract和astype(int)操作中,这些项就会被正确地转换为数字0,从而只统计了已支付的销售额。
关键点与注意事项
- 正则表达式的精确性:str.extract的强大之处在于正则表达式。确保你的正则表达式能够准确匹配你想要提取的部分,并且不会意外匹配到不相关的内容。例如,如果数字可能出现在字符串的中间或末尾,则需要调整正则表达式。
- expand=False的重要性:当正则表达式只包含一个捕获组时,expand=False会使str.extract返回一个Series,这通常更便于后续操作。如果设置为True(默认值),即使只有一个捕获组,也会返回一个DataFrame。
- 类型转换:从字符串中提取的数字默认是字符串类型。在进行任何数学运算(如求和、平均值)之前,务必使用astype(int)或astype(float)将其转换为数值类型。
- 处理缺失值或非匹配项:如果str.extract没有找到匹配项,它会返回NaN。在尝试使用astype(int)转换时,NaN会导致错误。在实际应用中,你可能需要在使用astype之前,通过fillna()来处理这些NaN值(例如,替换为0),或者使用astype(float)(可以接受NaN),或者使用pd.to_numeric(errors=’coerce’)来将无法转换的值变为NaN。本教程中的where方法是一个有效的预处理手段,可以避免NaN的产生。
总结
本教程演示了如何利用Pandas的str.extract方法结合正则表达式,有效地从格式不一致的字符串列中提取数值。通过将提取出的数据转换为适当的数值类型,并结合groupby()进行聚合,我们可以轻松地对非结构化数据进行清洗、转换和分析。这种技术在处理日志文件、网络爬取数据或任何包含混合文本和数字的数据集时都非常有用。掌握str.extract和正则表达式将大大提升你在Pandas中处理复杂字符串数据的能力。
go 正则表达式 ai 正则表达式 pandas Float Object 字符串 int 值类型 整数类型 字符串类型 类型转换 table