
本教程详细介绍了如何使用Pandas库高效处理包含混合数据类型(数字词汇和数值)的DataFrame列。文章将重点讲解如何通过正则表达式进行复杂的数据拆分,识别并有条件地将数字词汇转换为数值,并最终将处理后的数据整合到新的结构化列中,以解决数据清洗中常见的格式不一致问题。
在数据分析和处理中,我们经常会遇到包含非标准格式数据的列,例如一列中混合了文本描述的数字(如“three hundred and two”)和常规数值(如“203.0”),并且这些数据可能由多种分隔符连接。本教程将指导您如何使用Pandas结合正则表达式和word2number库来解决这类复杂的数据清洗任务,最终将原始列拆分为多个结构化、数值化的新列。
1. 问题描述与挑战
假设我们有一个DataFrame,其中包含类似cement_water和coarse_fine_aggregate这样的列。这些列的特点是:
- 混合数据类型:cement_water列可能包含数字词汇(如"three hundred and two")和浮点数(如"203.0")。
- 多重分隔符:不同行的数据可能使用不同的分隔符(例如;、,、_)来连接不同的数值。
- 目标:将这些混合格式的列拆分为独立的、纯数值的列(例如cement、water、coarse_aggregate、fine_aggregate)。
原始数据示例:
| cement_water | coarse_fine_aggregate |
|---|---|
| three hundred and two;203.0 | 974.0,817.0 |
| one hundred and fifty-one;184.4 | 992.0;815.9 |
| three hundred and sixty-two_164.9 | 944.7;755.8 |
期望输出:
| cement | water | coarse_aggregate | fine_aggregate |
|---|---|---|---|
| 302.0 | 203.0 | 974.0 | 817.0 |
| 151.0 | 184.4 | 992.0 | 815.9 |
| 362.0 | 164.9 | 944.7 | 755.8 |
直接使用简单的字符串分割和word2number转换可能会导致错误,特别是当word2number尝试转换一个已经是数字字符串(如"203.0")时,会抛出ValueError: No valid number words found!。
2. 解决方案概述
为了有效解决上述问题,我们将采取以下策略:
- 使用正则表达式提取数据:利用正则表达式的强大功能,一次性从原始字符串中提取出我们需要的各个部分,同时处理多种分隔符。
- 条件性地转换数字词汇:识别出哪些部分是数字词汇需要转换,哪些部分已经是数值字符串可以直接解析。
- 整合与类型转换:将提取和转换后的数据合并到新的DataFrame中,并确保所有列都转换为正确的数值类型。
3. 实现步骤与代码示例
首先,导入必要的库并创建示例DataFrame:
import pandas as pd
from word2number import w2n
import io
# 示例数据
data = """cement_water,coarse_fine_aggregate
three hundred and two;203.0,974.0,817.0
one hundred and fifty-one;184.4,992.0;815.9
three hundred and sixty-two_164.9,944.7;755.8
"""
df = pd.read_csv(io.StringIO(data))
print("原始DataFrame:")
print(df)3.1 处理 cement_water 列:提取并有条件转换
cement_water 列是挑战最大的部分,因为它混合了数字词汇和数值,并且可能使用不同的分隔符。我们将使用正则表达式来捕获两部分数据,然后对第一部分进行条件性转换。
-
使用正则表达式提取: 我们使用 str.extract() 配合正则表达式 r'(?P
.*)[;,_](?P \d+.?\d*)$'。 - (?P
.*):捕获分隔符前的所有字符作为 cement 部分。 - [;,_]:匹配任意一个分隔符(分号、逗号、下划线)。
- (?P
\d+.?\d*):捕获分隔符后的数字(整数或浮点数)作为 water 部分。 - $:确保匹配到字符串的末尾。
- (?P
-
条件性转换 cement 部分:
- 首先,尝试将提取出的 cement 部分直接转换为数值。如果失败(即它是一个数字词汇),则会产生 NaN。
- 利用 pd.to_numeric(..., errors='coerce') 的特性,我们可以识别出哪些值是数字词汇(转换后为 NaN)。
- 然后,只对这些 NaN 值对应的原始 cement 字符串应用 w2n.word_to_num 进行转换。
# 提取 cement_water 列 tmp = df['cement_water'].str.extract(r'(?P.*)[;,_](?P \d+.?\d*)$') # 尝试将 'cement' 列转换为数值,无法转换的会变成 NaN s = pd.to_numeric(tmp['cement'], errors='coerce') # 找出 'cement' 列中为 NaN 的行(即原始值是数字词汇的行) # 并且确保原始值不是空的(因为 extract 可能会生成空字符串) m = s.isna() & tmp['cement'].notna() # 对这些行应用 w2n.word_to_num 进行转换 tmp.loc[m, 'cement'] = tmp.loc[m, 'cement'].map(w2n.word_to_num) print("\n处理后的 tmp DataFrame (cement_water):") print(tmp)
3.2 处理 coarse_fine_aggregate 列:简单拆分
coarse_fine_aggregate 列相对简单,它只包含数值,并由 ; 或 , 或 _ 分隔。我们可以直接使用 str.split()。
# 拆分 coarse_fine_aggregate 列
coarse_fine_agg = df['coarse_fine_aggregate'].str.split('[;,_]', expand=True)
# 重命名列
coarse_fine_agg = coarse_fine_agg.rename(columns={0: 'coarse_aggregate', 1: 'fine_aggregate'})
print("\n处理后的 coarse_fine_agg DataFrame:")
print(coarse_fine_agg)3.3 合并结果并最终类型转换
最后,我们将 tmp 和 coarse_fine_agg 这两个处理过的DataFrame通过 pd.concat 合并起来,并将所有列转换为浮点数类型。
# 合并所有处理后的数据
out = pd.concat([tmp, coarse_fine_agg], axis=1)
# 将所有列转换为浮点数类型
out = out.astype(float)
print("\n最终转换后的DataFrame:")
print(out)4. 完整代码示例
将上述步骤整合在一起,形成一个完整的解决方案:
import pandas as pd from word2number import w2n import io # 示例数据 data = """cement_water,coarse_fine_aggregate three hundred and two;203.0,974.0,817.0 one hundred and fifty-one;184.4,992.0;815.9 three hundred and sixty-two_164.9,944.7;755.8 """ df = pd.read_csv(io.StringIO(data)) # 1. 处理 'cement_water' 列 # 提取 cement_water 列,捕获分隔符前后的内容 tmp = df['cement_water'].str.extract(r'(?P.*)[;,_](?P \d+.?\d*)$') # 尝试将 'cement' 列转换为数值,无法转换的会变成 NaN s = pd.to_numeric(tmp['cement'], errors='coerce') # 找出 'cement' 列中为 NaN 的行(即原始值是数字词汇的行) m = s.isna() & tmp['cement'].notna() # 对这些行应用 w2n.word_to_num 进行转换 tmp.loc[m, 'cement'] = tmp.loc[m, 'cement'].map(w2n.word_to_num) # 2. 处理 'coarse_fine_aggregate' 列 # 拆分 coarse_fine_aggregate 列,支持多种分隔符 coarse_fine_agg = df['coarse_fine_aggregate'].str.split('[;,_]', expand=True) # 重命名列 coarse_fine_agg = coarse_fine_agg.rename(columns={0: 'coarse_aggregate', 1: 'fine_aggregate'}) # 3. 合并结果并转换为浮点数 out = pd.concat([tmp, coarse_fine_agg], axis=1) out = out.astype(float) print("最终处理结果:") print(out)
5. 注意事项与总结
-
正则表达式的精准性:选择合适的正则表达式至关重要。r'(?P
.*)[;,_](?P \d+.?\d*)$' 能够灵活处理多种分隔符,并确保 water 部分是数字。 - pd.to_numeric(errors='coerce') 的妙用:这是识别混合数据类型中哪些是数字词汇的关键。它允许我们只对需要转换的部分应用 w2n.word_to_num,从而避免 ValueError。
- 链式操作与可读性:虽然可以将所有操作链式组合起来,但为了教程的清晰性,这里分步进行了展示。在实际生产代码中,可以根据团队规范和复杂性进行调整。
- 错误处理:本教程假设数据格式基本符合预期。在更复杂的场景中,您可能需要添加额外的错误处理逻辑,例如当正则表达式无法匹配任何数据时。
- 库依赖:确保您的环境中安装了 pandas 和 word2number 库 (pip install pandas word2number)。
通过本教程,您应该能够掌握在Pandas中处理复杂混合数据类型、进行条件性数据转换以及利用正则表达式进行高效数据拆分的方法。这些技术在实际数据清洗工作中非常实用。










