
本文深入探讨了在Pandas DataFrame中,如何根据现有列(如字符串中的数字部分)的特定条件,高效地创建或更新新列。文章将详细介绍如何结合str.extract、pd.cut和np.log10等工具,实现基于数值范围或数字位数的高级条件赋值,从而提升数据处理的灵活性和效率。
在数据分析和处理过程中,我们经常需要根据dataframe中某一列的复杂条件来生成或更新另一列的值。例如,从一个包含混合字符串和数字的列中提取数字,并根据这些数字的特点(如数值大小范围或数字的位数)进行分类赋值。本教程将展示两种高效且专业的pandas解决方案来解决这类问题。
初始数据准备
首先,我们构建一个示例DataFrame,它包含Server和Port两列。Port列是一个字符串,其中包含”Ethernet”前缀和随后的一个或多个数字。
import pandas as pdimport numpy as npdata = { 'Server': ['Ser123', 'Ser123', 'Ser123', 'Ser123', 'Serabc', 'Serabc', 'Serabc', 'Serabc'], 'Port': ['Ethernet3', 'Ethernet4', 'Ethernet12', 'Ethernet567', 'Ethernet2', 'Ethernet34', 'Ethernet458', 'Ethernet5689']}df = pd.DataFrame(data)print("原始DataFrame:")print(df)
输出:
原始DataFrame: Server Port0 Ser123 Ethernet31 Ser123 Ethernet42 Ser123 Ethernet123 Ser123 Ethernet5674 Serabc Ethernet25 Serabc Ethernet346 Serabc Ethernet4587 Serabc Ethernet5689
我们的目标是创建一个名为function_val的新列,其值将根据Port列中数字部分的特性来决定。具体规则如下:
如果数字是1位(例如Ethernet3),function_val为’5k’。如果数字是2位(例如Ethernet12),function_val为’10k’。如果数字是3位或更多(例如Ethernet567),function_val为’20k’。
解决方案一:基于数值范围的分类赋值 (str.extract + pd.cut)
这种方法适用于根据提取出的数字的数值大小范围进行分类。
提取数字: 使用Series.str.extract()结合正则表达式r'(d+)$’来提取Port列末尾的数字。(d+)捕获一个或多个数字,$匹配字符串的末尾。expand=False确保返回一个Series而不是DataFrame。类型转换: 将提取出的字符串数字转换为整数类型,以便进行数值比较。区间划分与赋值: 使用pd.cut()函数将数字划分到预定义的区间(bins)中,并为每个区间分配相应的标签(labels)。
# 定义数值区间和对应的标签bins = [0, 10, 100, np.inf] # 0 < x <= 10, 10 < x <= 100, 100 < x <= inflabels = ['5k', '10k', '20k']# 提取数字,转换为整数,并使用pd.cut进行分类赋值df['function_val_cut'] = pd.cut( df['Port'].str.extract(r'(d+)$', expand=False).astype(int), bins=bins, labels=labels, right=True # 默认右闭合,即 (bin_i, bin_i+1])print("n使用pd.cut分类后的DataFrame:")print(df)
输出:
使用pd.cut分类后的DataFrame: Server Port function_val_cut0 Ser123 Ethernet3 5k1 Ser123 Ethernet4 5k2 Ser123 Ethernet12 10k3 Ser123 Ethernet567 20k4 Serabc Ethernet2 5k5 Serabc Ethernet34 10k6 Serabc Ethernet458 20k7 Serabc Ethernet5689 NaN
注意事项:
bins定义了区间的边界。例如,[0, 10, 100, np.inf]会创建三个区间:(0, 10], (10, 100], (100, inf)。right=True(默认值)表示区间是右闭合的,即bins[i]到bins[i+1]的区间包含bins[i+1]但不包含bins[i]。在上述示例中,Ethernet5689中的5689超出了[0, 10, 100, np.inf]定义的最高区间,因此被赋值为NaN。如果需要处理这种情况,可以调整bins的定义或在pd.cut之后进行进一步处理。
解决方案二:基于数字位数的条件赋值 (str.extract + np.log10 + np.ceil + map)
这种方法适用于根据提取出的数字的位数进行分类。
提取数字和类型转换: 与方法一相同,提取数字并转换为整数。计算位数: 利用数学函数np.log10和np.ceil来计算一个正整数的位数。对于一个正整数N,其位数为ceil(log10(N+1))。例如,N=3 (log10(4) ≈ 0.6) -> ceil(0.6) = 1位。例如,N=12 (log10(13) ≈ 1.1) -> ceil(1.1) = 2位。例如,N=567 (log10(568) ≈ 2.7) -> ceil(2.7) = 3位。映射赋值: 使用Series.map()函数将计算出的位数映射到预定义的标签字典。
# 定义位数和对应的标签映射labels_by_digits = {1: '5k', 2: '10k', 3: '20k', 4: '20k'} # 假设4位也对应20k# 提取数字,转换为整数,计算位数,并使用map进行赋值df['function_val_digits'] = ( np.ceil(np.log10(df['Port'].str.extract(r'(d+)$', expand=False).astype(int) + 1)) .map(labels_by_digits))print("n使用位数映射分类后的DataFrame:")print(df)
输出:
使用位数映射分类后的DataFrame: Server Port function_val_cut function_val_digits0 Ser123 Ethernet3 5k 5k1 Ser123 Ethernet4 5k 5k2 Ser123 Ethernet12 10k 10k3 Ser123 Ethernet567 20k 20k4 Serabc Ethernet2 5k 5k5 Serabc Ethernet34 10k 10k6 Serabc Ethernet458 20k 20k7 Serabc Ethernet5689 NaN 20k
注意事项:
labels_by_digits字典需要包含所有可能出现的位数及其对应的标签。如果计算出的位数在字典中没有对应的键,map函数将返回NaN。这种方法对于严格按照数字位数进行分类的场景非常有效。
总结与最佳实践
本文展示了在Pandas DataFrame中根据复杂条件(特别是从字符串中提取数字并基于其数值或位数)创建新列的两种强大方法:
str.extract + pd.cut: 适用于根据数值的大小范围进行分类。当需要将连续的数值数据离散化到预定义区间时,这是一个理想的选择。str.extract + np.log10 + np.ceil + map: 适用于根据数字的位数进行分类。当分类逻辑与数字的长度而非具体数值范围更相关时,此方法更为直接和高效。
在实际应用中,选择哪种方法取决于具体的业务逻辑和分类需求。无论哪种方法,以下几点都是通用的最佳实践:
正则表达式的精准性: 确保str.extract中的正则表达式能够准确无误地捕获目标数据。数据类型转换: 在进行数值计算或比较之前,务必将提取出的字符串数据转换为正确的数值类型(如int或float)。错误处理: 考虑正则表达式未能匹配、类型转换失败或数值超出预设范围/映射字典的情况,并根据需要添加错误处理逻辑(例如,使用fillna()处理NaN值)。可读性与维护性: 对于复杂的条件逻辑,将bins、labels或映射字典定义为单独的变量,可以提高代码的可读性和可维护性。
通过掌握这些Pandas技巧,您可以更高效、更灵活地处理和转换DataFrame中的数据,满足各种复杂的数据处理需求。
以上就是Pandas DataFrame中基于字符串数字的高级条件赋值技巧的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1376863.html
微信扫一扫
支付宝扫一扫