
在数据分析和处理过程中,我们经常需要将分散在不同数据集中的信息关联起来。pandas库提供了强大的数据合并(merge)和连接(join)功能,但有时关联键的格式并不直接匹配,例如,一个dataframe中的键是包含数字的字符串(如“1st”),而另一个dataframe的键是纯数字索引。本文将详细阐述如何利用pandas的字符串处理和映射功能,优雅地解决这类复杂条件下的数据关联问题。
假设我们有两个DataFrame,df1和df2,它们的结构如下:
df1包含birthdate和ceremony_number两列,其中ceremony_number是包含数字和文本的字符串。 df2包含一个日期列dates,其索引(index)代表了某个事件的序号。
我们的目标是:根据df1中ceremony_number列里提取出的数字(例如从“1st”提取出“1”),去匹配df2的索引,并将df2中对应的dates值作为新列date_oscar添加到df1中。
示例代码:初始DataFrame构建
import pandas as pd
# 原始 df1 数据
data1 = {'birthdate': {0: '9/30/1895', 1: '7/23/1884', 2: '3/29/1889',
3: '4/10/1868', 4: '4/8/1892'},
'ceremony_number': {0: '1st', 1: '1st', 2: '2nd', 3: '3rd', 4: '2nd'}}
df1 = pd.DataFrame(data1)
# 原始 df2 数据 (注意其索引从1开始)
data2 = {'dates': {1: '1929-05-16', 2: '1930-04-03', 3: '1930-11-05'}}
df2 = pd.DataFrame(data2)
print("原始 df1:")
print(df1)
print("\n原始 df2:")
print(df2)输出:
原始 df1:
birthdate ceremony_number
0 9/30/1895 1st
1 7/23/1884 1st
2 3/29/1889 2nd
3 4/10/1868 3rd
4 4/8/1892 2nd
原始 df2:
dates
1 1929-05-16
2 1930-04-03
3 1930-11-05直接使用pd.merge()函数无法完成此任务,因为df1['ceremony_number']是字符串,而df2的匹配键是整数索引。此外,尝试通过循环df1.iterrows()来逐行匹配并追加数据是一种低效且容易出错的方法,应尽量避免在Pandas中使用。
解决此问题的核心在于两个步骤:首先,从df1的ceremony_number列中精确提取出数字部分;其次,利用Pandas的Series.map()功能将这些提取出的数字与df2的索引进行匹配,并获取对应的日期值。
在进行任何日期相关的操作之前,将日期字符串转换为Pandas的datetime类型是一个良好的实践。这不仅能确保数据的一致性,也便于后续的日期计算或格式化。
# 将日期列转换为 datetime 类型
df1['birthdate'] = pd.to_datetime(df1['birthdate'], format='%m/%d/%Y')
df2['dates'] = pd.to_datetime(df2['dates'], format='%Y-%m-%d')
print("\n转换日期类型后的 df1:")
print(df1)
print("\n转换日期类型后的 df2:")
print(df2)输出:
转换日期类型后的 df1:
birthdate ceremony_number
0 1895-09-30 1st
1 1884-07-23 1st
2 1889-03-29 2nd
3 1868-04-10 3rd
4 1892-04-08 2nd
转换日期类型后的 df2:
dates
1 1929-05-16
2 1930-04-03
3 1930-11-05我们需要从df1['ceremony_number']列中的“1st”、“2nd”等字符串中提取出数字“1”、“2”等。Pandas的Series.str.extract()方法结合正则表达式是实现这一目标的理想工具。
# 从 'ceremony_number' 中提取数字并转换为整数
extracted_num = df1['ceremony_number'].str.extract('^(\d+)', expand=False).astype(int)
print("\n从 'ceremony_number' 提取出的数字键:")
print(extracted_num)输出:
从 'ceremony_number' 提取出的数字键: 0 1 1 1 2 2 3 3 4 2 Name: ceremony_number, dtype: int32
现在我们有了df1中用于匹配的数字键(extracted_num Series),以及df2中作为查找表的dates列(其索引是匹配键)。Pandas的Series.map()方法是执行此映射操作的完美选择。
当map()方法接收一个Series作为参数时,它会使用该参数Series的索引作为查找键,其值作为返回结果。在本例中,df2['dates']的索引是1, 2, 3,对应的值是日期。extracted_num中的每个值都会在df2.index中查找,并返回df2['dates']中对应的值。
# 使用提取出的数字作为键,通过 df2['dates'] 进行映射 df1['date_oscar'] = extracted_num.map(df2['dates'])
将上述所有步骤整合起来,形成一个完整的解决方案代码块:
import pandas as pd
# 1. 原始数据准备
data1 = {'birthdate': {0: '9/30/1895', 1: '7/23/1884', 2: '3/29/1889',
3: '4/10/1868', 4: '4/8/1892'},
'ceremony_number': {0: '1st', 1: '1st', 2: '2nd', 3: '3rd', 4: '2nd'}}
df1 = pd.DataFrame(data1)
data2 = {'dates': {1: '1929-05-16', 2: '1930-04-03', 3: '1930-11-05'}}
df2 = pd.DataFrame(data2)
# 2. 数据类型标准化
df1['birthdate'] = pd.to_datetime(df1['birthdate'], format='%m/%d/%Y')
df2['dates'] = pd.to_datetime(df2['dates'], format='%Y-%m-%d')
# 3. 从 'ceremony_number' 中提取数字并转换为整数
num = df1['ceremony_number'].str.extract('^(\d+)', expand=False).astype(int)
# 4. 使用提取出的数字作为键,通过 df2['dates'] 进行映射
df1['date_oscar'] = num.map(df2['dates'])
print("\n最终 df1 (包含 'date_oscar' 列):")
print(df1)最终输出:
最终 df1 (包含 'date_oscar' 列): birthdate ceremony_number date_oscar 0 1895-09-30 1st 1929-05-16 1 1884-07-23 1st 1929-05-16 2 1889-03-29 2nd 1930-04-03 3 1868-04-10 3rd 1930-11-05 4 1892-04-08 2nd 1930-04-03
从结果可以看出,df1成功地添加了date_oscar列,并且其中的日期值根据ceremony_number与df2的索引正确匹配。例如,ceremony_number为“1st”的行被映射到了df2索引为1的日期1929-05-16。
本文提供了一个清晰、高效的Pandas解决方案,用于处理两个DataFrame之间基于字符串提取和映射的条件关联。通过将ceremony_number列中的数字部分提取出来并转换为整数,然后利用Series.map()功能与df2的索引进行匹配,我们成功地将所需数据合并到df1中。这种方法不仅解决了特定场景下的数据关联难题,也体现了Pandas在数据处理方面的强大功能和灵活性,是每个数据分析师和工程师都应掌握的关键技能。
以上就是Pandas数据合并技巧:基于字符串提取和映射实现条件关联的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号