
本文详细阐述了如何利用pandas库,结合`melt`、`merge_asof`和`pivot`等操作,根据另一个dataframe中定义的日期范围条件,灵活地填充目标dataframe中的数据。通过将宽格式数据转换为长格式进行近似合并,并结合精确的日期范围检查,实现复杂的数据匹配与填充需求。
在数据分析和处理过程中,我们经常会遇到需要根据特定条件从一个数据集填充或更新另一个数据集的场景。当这些条件涉及日期范围时,问题会变得更具挑战性。本教程将介绍一种高效且灵活的方法,利用Pandas的melt、merge_asof和pivot功能,解决根据日期范围条件从一个DataFrame填充另一个DataFrame数据的需求。
假设我们有两个DataFrame:
我们的目标是创建一个新的DataFrame df3,其结构与 df2 类似,但只保留 df2 中在 df1 定义的有效日期范围内的公司数据,超出范围的数据应显示为 NaN。
以下是示例数据:
import pandas as pd
# df1: 定义公司及其有效日期范围
data1 = {
'company': ['a', 'b', 'c', 'd'],
'start date': ['2023-01-02', '2023-01-05', '2023-01-04', '2023-01-03'],
'end date': ['2023-01-06', '2023-01-12', '2023-01-13', '2023-01-10']
}
df1 = pd.DataFrame(data1)
# df2: 包含每日数据的DataFrame
data2 = {
'DATE': ['2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05',
'2023-01-06', '2023-01-09', '2023-01-10', '2023-01-11',
'2023-01-12', '2023-01-13'],
'a': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'b': [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
'c': [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
'd': [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
}
df2 = pd.DataFrame(data2)
print("df1:")
print(df1)
print("\ndf2:")
print(df2)在进行任何日期相关的操作之前,确保所有日期列都被正确地识别为Pandas的datetime类型至关重要。这可以避免潜在的类型不匹配错误,并允许使用日期时间特有的功能。
df1['start date'] = pd.to_datetime(df1['start date'])
df1['end date'] = pd.to_datetime(df1['end date'])
df2['DATE'] = pd.to_datetime(df2['DATE'])
print("\ndf1 (日期转换后):")
print(df1)
print("\ndf2 (日期转换后):")
print(df2)为了将 df2 中的数据与 df1 中的日期范围进行匹配,我们需要将 df2 从宽格式(每列代表一个公司)转换为长格式(一列代表公司,另一列代表其值)。melt 函数非常适合这个任务。
接下来,我们将使用 pd.merge_asof 进行近似合并。merge_asof 是一种特殊的合并,它在左DataFrame的键值“接近”右DataFrame的键值时进行合并。这对于日期范围查找非常有用。
然而,merge_asof只处理了起始日期条件。我们还需要确保合并后的数据在 end date 范围内。这通过 .assign(value=tmp['value'].where(tmp['DATE'].le(tmp['end date']))) 来实现。where 方法会根据条件保留值,否则替换为NaN。
最后,使用 pivot 将数据从长格式重新转换回所需的宽格式,并清理列名。
# 将df2转换为长格式,并按日期排序
tmp = df2.melt('DATE', var_name='company').sort_values('DATE')
# 将df1按起始日期排序
df1_sorted = df1.sort_values('start date')
# 进行merge_asof合并,基于公司和起始日期
# merge_asof 会找到每个公司在df1中start date <= tmp['DATE']的最近一行进行合并
merged_df = pd.merge_asof(tmp, df1_sorted,
by='company',
left_on='DATE',
right_on='start date')
# 应用结束日期条件:如果当前日期(merged_df['DATE'])超出结束日期(merged_df['end date']),则将值设为NaN
final_df = merged_df.assign(value=merged_df['value'].where(merged_df['DATE'].le(merged_df['end date'])))
# 将数据透视回宽格式,以DATE为索引,company为列名,value为值
df3 = final_df.pivot(index='DATE', columns='company', values='value')
# 清理列名和索引
df3 = df3.rename_axis(columns=None).reset_index()
print("\ndf3 (最终结果):")
print(df3)import pandas as pd
# 1. 数据初始化
data1 = {
'company': ['a', 'b', 'c', 'd'],
'start date': ['2023-01-02', '2023-01-05', '2023-01-04', '2023-01-03'],
'end date': ['2023-01-06', '2023-01-12', '2023-01-13', '2023-01-10']
}
df1 = pd.DataFrame(data1)
data2 = {
'DATE': ['2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05',
'2023-01-06', '2023-01-09', '2023-01-10', '2023-01-11',
'2023-01-12', '2023-01-13'],
'a': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'b': [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
'c': [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
'd': [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
}
df2 = pd.DataFrame(data2)
print("原始 df1:")
print(df1)
print("\n原始 df2:")
print(df2)
# 2. 日期列类型转换
df1['start date'] = pd.to_datetime(df1['start date'])
df1['end date'] = pd.to_datetime(df1['end date'])
df2['DATE'] = pd.to_datetime(df2['DATE'])
# 3. 数据重塑与条件合并
# 将df2转换为长格式,并按日期排序,为merge_asof做准备
tmp = df2.melt('DATE', var_name='company', value_name='value_from_df2').sort_values('DATE')
# 将df1按起始日期排序,也为merge_asof做准备
df1_sorted = df1.sort_values('start date')
# 使用merge_asof进行近似合并
# by='company'确保每个公司独立匹配
# left_on='DATE'是tmp中的日期,right_on='start date'是df1_sorted中的起始日期
merged_df = pd.merge_asof(tmp, df1_sorted,
by='company',
left_on='DATE',
right_on='start date')
# 应用结束日期条件:如果当前日期超出结束日期,则将值设为NaN
# 这里的value_from_df2是df2中原始的值
final_df = merged_df.assign(
value_filtered=merged_df['value_from_df2'].where(
(merged_df['DATE'] >= merged_df['start date']) &
(merged_df['DATE'] <= merged_df['end date'])
)
)
# 将数据透视回宽格式
df3 = final_df.pivot(index='DATE', columns='company', values='value_filtered')
# 清理列名和索引
df3 = df3.rename_axis(columns=None).reset_index()
print("\n最终结果 df3:")
print(df3)通过上述步骤,我们能够有效地根据复杂的日期范围条件,从一个DataFrame中提取并填充数据到另一个DataFrame,从而满足多样化的数据处理需求。
以上就是使用Pandas基于日期范围条件填充DataFrame数据的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号