Pandas数据清洗:高效处理混合分隔符与文本数字的列拆分与转换

霞舞
发布: 2025-11-11 12:13:00
原创
338人浏览过

Pandas数据清洗:高效处理混合分隔符与文本数字的列拆分与转换

本教程旨在解决pandas数据处理中常见的挑战:如何将包含混合分隔符和文本(英文单词)表示数字的单列数据,拆分成多个独立的数值列。我们将探讨使用正则表达式提取数据、结合`word2number`库将文本数字转换为数值,并利用pandas的强大功能进行高效的数据清洗、类型转换与结构重塑,确保数据准确性和可用性。

在数据分析和机器学习项目中,原始数据往往不够规整。一个常见的问题是,单个列中可能包含由多种分隔符连接的多个逻辑值,并且这些值可能以文本(如“three hundred and two”)和数字(如“203.0”)的混合形式存在。本教程将指导您如何使用Python的Pandas库结合正则表达式和word2number库来高效地处理这类复杂的数据清洗任务。

问题场景描述

假设我们有一个DataFrame,其中包含类似cement_water和coarse_fine_aggregate这样的列。 cement_water列的值可能形如three hundred and two;203.0或one hundred and fifty-one;184.4,甚至three hundred and sixty-two_164.9。这里存在以下挑战:

  1. 混合分隔符: 值之间可能使用;、,或_等不同字符进行分隔。
  2. 文本数字: 部分数值以英文单词形式(如three hundred and two)存在,需要转换为实际的数字。
  3. 类型转换: 最终所有拆分出的列都应为数值类型。

我们的目标是将这些列转换为以下结构:

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

初始尝试与遇到的问题

许多用户在处理这类问题时,可能会尝试先统一分隔符,然后使用str.split()进行拆分,最后再对文本数字进行转换。

import pandas as pd
from word2number import w2n

# 假设df已加载
# df = pd.read_csv('your_data.csv')

# 模拟数据
data = {
    'cement_water': ['three hundred and two;203.0', 'one hundred and fifty-one;184.4', 'three hundred and sixty-two_164.9'],
    'coarse_fine_aggregate': ['974.0,817.0', '992.0;815.9', '944.7;755.8']
}
df = pd.DataFrame(data)

def convert_words_to_numbers(text):
    # 尝试统一分隔符并分割,然后转换
    # 这种方法存在问题,因为w2n.word_to_num不能处理纯数字字符串
    words = text.replace('_', ' ').replace(';', ' ').replace(',', ' ').split()
    converted_words = []
    for word in words:
        if word.isalpha(): # 如果是字母,尝试转换为数字
            converted_words.append(str(w2n.word_to_num(word)))
        else: # 否则直接添加
            converted_words.append(word)
    return ' '.join(converted_words)

# 应用转换函数
df['cement_water_processed'] = df['cement_water'].apply(lambda x: convert_words_to_numbers(x))

# 尝试拆分
# df[['cement', 'water']] = df['cement_water_processed'].str.split(' ', expand=True)
# 这段代码会因为w2n.word_to_num无法处理"203.0"等纯数字字符串而报错,
# 即使修改了convert_words_to_numbers函数,也可能因为分隔符处理不当导致问题。
登录后复制

上述代码尝试通过统一分隔符后进行split,并使用word2number转换。然而,w2n.word_to_num()函数设计用于将英文单词转换为数字,例如"two hundred",但它无法处理已经是数字格式的字符串,如"203.0"。如果尝试将"203.0"传递给w2n.word_to_num(),就会抛出ValueError: No valid number words found!。这表明我们需要更精细的策略来区分和处理文本数字和纯数字字符串。

解决方案:结合正则表达式与条件转换

为了解决上述问题,我们可以采用以下更健壮的方法:

  1. 使用正则表达式精确提取: 利用str.extract()结合正则表达式,可以同时处理多种分隔符,并区分文本部分和数字部分。
  2. 有条件地应用word2number: 仅对那些确实是文本数字的部分应用w2n.word_to_num()。
  3. 统一数据类型: 最终将所有目标列转换为浮点数。

方案一:针对特定模式的直接提取与转换

如果我们的数据模式相对固定,即一个文本数字后跟一个分隔符,再跟一个纯数字,可以使用如下正则表达式。

import pandas as pd
from word2number import w2n

# 模拟数据
data = {
    'cement_water': ['three hundred and two;203.0', 'one hundred and fifty-one;184.4', 'three hundred and sixty-two_164.9'],
    'coarse_fine_aggregate': ['974.0,817.0', '992.0;815.9', '944.7;755.8']
}
df = pd.DataFrame(data)

# 1. 使用正则表达式提取 cement_water 列
# (?P<cement>.*) 捕获分隔符前的所有内容作为 'cement'
# [;,_] 匹配任意一个分隔符
# (?P<water>\d+.?\d*)$ 捕获分隔符后的数字(整数或浮点数)作为 'water',并确保在行尾
tmp_cement_water = df['cement_water'].str.extract(r'(?P<cement>.*)[;,_](?P<water>\d+.?\d*)$')

# 2. 对 coarse_fine_aggregate 列进行拆分
# [;,_] 匹配任意一个分隔符进行拆分
tmp_coarse_fine = df['coarse_fine_aggregate'].str.split('[;,_]', expand=True) \
                                             .rename(columns={0: 'coarse_aggregate', 1: 'fine_aggregate'})

# 3. 将 'cement' 列的文本数字转换为数值
# 使用 .map() 配合 w2n.word_to_num 对 'cement' 列进行转换
tmp_cement_water['cement'] = tmp_cement_water['cement'].map(w2n.word_to_num)

# 4. 合并所有结果列并转换为浮点型
out = pd.concat([tmp_cement_water, tmp_coarse_fine], axis=1).astype(float)

print("方案一结果:")
print(out)
登录后复制

输出示例:

怪兽AI数字人
怪兽AI数字人

数字人短视频创作,数字人直播,实时驱动数字人

怪兽AI数字人 44
查看详情 怪兽AI数字人
   cement  water  coarse_aggregate  fine_aggregate
0   302.0  203.0             974.0           817.0
1   151.0  184.4             992.0           815.9
2   362.0  164.9             944.7           755.8
登录后复制

这个方案的关键在于正则表达式r'(?P<cement>.*)[;,_](?P<water>\d+.?\d*)$',它能够将文本数字部分(cement)与纯数字部分(water)有效分离。这样,w2n.word_to_num只作用于它能够处理的文本数字。

方案二:更通用的条件转换(推荐)

在某些情况下,cement部分可能也混合了纯数字字符串(尽管本例中不是),或者数据模式更复杂。为了提高鲁棒性,我们可以采用一个更通用的方法,即先尝试将列转换为数字,失败后再使用word2number。

import pandas as pd
from word2number import w2n

# 模拟数据
data = {
    'cement_water': ['three hundred and two;203.0', 'one hundred and fifty-one;184.4', 'three hundred and sixty-two_164.9'],
    'coarse_fine_aggregate': ['974.0,817.0', '992.0;815.9', '944.7;755.8']
}
df = pd.DataFrame(data)

# 1. 使用正则表达式提取 cement_water 列
tmp = df['cement_water'].str.extract(r'(?P<cement>.*)[;,_](?P<water>\d+.?\d*)$')

# 2. 尝试将 'cement' 列直接转换为数值,无法转换的标记为 NaN
s = pd.to_numeric(tmp['cement'], errors='coerce')

# 3. 找出那些无法转换为数值(即为 NaN)且原始数据不为空的行
m = s.isna() & df['cement_water'].notna()

# 4. 仅对这些无法直接转换为数值的行,使用 w2n.word_to_num 进行转换
# 注意:这里假设tmp['cement']中m对应的元素是word string,如果不是,w2n.word_to_num会报错
# 实际上,由于前面的regex已经将纯数字部分提取给了'water',这里'cement'通常都是word string
tmp.loc[m, 'cement'] = df.loc[m, 'cement_water'].map(lambda x: w2n.word_to_num(x.split('[;,_]')[0]) if isinstance(x, str) else x)
# 修正:更准确的做法是使用tmp['cement']而不是df['cement_water'],因为tmp['cement']已经包含了提取出的word string
tmp.loc[m, 'cement'] = tmp.loc[m, 'cement'].map(w2n.word_to_num)


# 5. 对 coarse_fine_aggregate 列进行拆分
tmp_coarse_fine = df['coarse_fine_aggregate'].str.split('[;,_]', expand=True) \
                                             .rename(columns={0: 'coarse_aggregate', 1: 'fine_aggregate'})

# 6. 合并所有结果列并转换为浮点型
out = pd.concat([tmp, tmp_coarse_fine], axis=1).astype(float)

print("\n方案二结果:")
print(out)
登录后复制

输出示例:

     cement  water  coarse_aggregate  fine_aggregate
0     302.0  203.0             974.0           817.0
1     151.0  184.4             992.0           815.9
2     362.0  164.9             944.7           755.8
登录后复制

方案二的优势在于其灵活性。它首先尝试最直接的数值转换,只有当转换失败时(说明是文本数字),才调用word2number。这避免了不必要的word2number调用,并能处理更复杂的数据混合情况。

关键注意事项与总结

  1. 正则表达式的精准性: 正则表达式是此解决方案的核心。r'(?P<name>pattern)'语法允许您命名捕获组,这使得后续处理更加方便。根据您的数据模式,可能需要调整正则表达式以精确匹配。例如,[;,_]可以匹配分号、逗号或下划线中的任意一个作为分隔符。\d+.?\d*用于匹配整数或浮点数。
  2. word2number库: 确保已安装word2number (pip install word2number)。它对于处理英文文本数字非常有效,但请记住它不能处理纯数字字符串。
  3. pd.to_numeric(errors='coerce'): 这是一个强大的工具,可以尝试将Series转换为数值类型。当遇到无法转换的值时,errors='coerce'参数会将其替换为NaN,这使得我们可以方便地识别并进一步处理这些异常值。
  4. 数据类型转换: 最终使用.astype(float)确保所有新生成的列都是浮点数类型,这对于后续的数值计算和分析至关重要。
  5. 性能考虑: 对于非常大的数据集,链式操作和多次apply可能会影响性能。上述解决方案中,通过矢量化的Pandas操作(如str.extract, str.split, map, pd.to_numeric, loc)可以获得较好的性能。
  6. 错误处理: 在实际应用中,如果word2number遇到它无法识别的文本(例如拼写错误或非数字文本),仍然可能抛出错误。您可能需要添加额外的错误捕获机制,例如在map函数中使用try-except块。

通过本教程,您应该能够熟练地处理Pandas中包含混合分隔符和文本数字的复杂列拆分与转换任务,从而为后续的数据分析奠定坚实的基础。

以上就是Pandas数据清洗:高效处理混合分隔符与文本数字的列拆分与转换的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号