0

0

使用Pandas基于日期范围条件填充DataFrame数据

霞舞

霞舞

发布时间:2025-10-18 14:35:22

|

209人浏览过

|

来源于php中文网

原创

使用Pandas基于日期范围条件填充DataFrame数据

本文详细阐述了如何利用pandas库,结合`melt`、`merge_asof`和`pivot`等操作,根据另一个dataframe中定义的日期范围条件,灵活地填充目标dataframe中的数据。通过将宽格式数据转换为长格式进行近似合并,并结合精确的日期范围检查,实现复杂的数据匹配与填充需求。

引言

在数据分析和处理过程中,我们经常会遇到需要根据特定条件从一个数据集填充或更新另一个数据集的场景。当这些条件涉及日期范围时,问题会变得更具挑战性。本教程将介绍一种高效且灵活的方法,利用Pandas的melt、merge_asof和pivot功能,解决根据日期范围条件从一个DataFrame填充另一个DataFrame数据的需求。

数据准备

假设我们有两个DataFrame:

  • df1 包含公司及其对应的有效日期范围(start date 和 end date)。
  • df2 包含每日数据,其中列名为公司名称,行索引为日期。

我们的目标是创建一个新的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)

核心实现步骤

1. 日期列类型转换

在进行任何日期相关的操作之前,确保所有日期列都被正确地识别为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)

2. 数据重塑与条件合并

为了将 df2 中的数据与 df1 中的日期范围进行匹配,我们需要将 df2 从宽格式(每列代表一个公司)转换为长格式(一列代表公司,另一列代表其值)。melt 函数非常适合这个任务。

VidAU
VidAU

VidAU AI 是一款AI驱动的数字人视频创作平台,旨在简化视频内容创作流程

下载

接下来,我们将使用 pd.merge_asof 进行近似合并。merge_asof 是一种特殊的合并,它在左DataFrame的键值“接近”右DataFrame的键值时进行合并。这对于日期范围查找非常有用。

  • df2.melt('DATE', var_name='company'):将df2转换为长格式,DATE列保持不变,其他列名(公司名称)变为company列的值,对应的数据变为value列的值。
  • .sort_values('DATE'):merge_asof要求两个DataFrame都按合并键排序。这里我们按DATE排序。
  • df1.sort_values('start date'):同样,df1也需要按其合并键start date排序。
  • pd.merge_asof(..., by='company', left_on='DATE', right_on='start date'):
    • by='company':指定在合并时,对于每个company,独立进行DATE和start date的近似匹配。
    • left_on='DATE':df2(长格式)中用于匹配的日期列。
    • right_on='start date':df1中用于匹配的起始日期列。merge_asof将找到df1中start date小于或等于df2中DATE的最近一行进行合并。

然而,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)

注意事项与总结

  1. 日期类型转换:这是最关键的第一步。不正确的日期类型会导致合并失败或结果不准确。
  2. 数据排序:pd.merge_asof 要求用于合并的键(left_on 和 right_on)在两个DataFrame中都必须是升序排列的。
  3. merge_asof 的行为:merge_asof 默认会找到 right_on 列中小于或等于 left_on 列的最近一个值进行合并。它只处理了起始日期条件,因此需要额外的 where 条件来检查结束日期。
  4. by 参数:在有多个分组(如本例中的company)时,使用 by 参数确保在每个分组内部独立进行近似合并,这对于维护数据的逻辑完整性至关重要。
  5. melt 和 pivot:这两个函数在处理宽格式和长格式数据转换时非常强大,是解决此类问题的常用组合。melt 将数据“堆叠”起来,方便进行逐行操作或合并;pivot 则将其“展开”回所需的表格形式。
  6. 性能:对于非常大的数据集,melt 和 pivot 操作可能会消耗较多内存和计算资源。但在大多数常见场景下,这种方法是高效且可读性强的。

通过上述步骤,我们能够有效地根据复杂的日期范围条件,从一个DataFrame中提取并填充数据到另一个DataFrame,从而满足多样化的数据处理需求。

相关专题

更多
Python 时间序列分析与预测
Python 时间序列分析与预测

本专题专注讲解 Python 在时间序列数据处理与预测建模中的实战技巧,涵盖时间索引处理、周期性与趋势分解、平稳性检测、ARIMA/SARIMA 模型构建、预测误差评估,以及基于实际业务场景的时间序列项目实操,帮助学习者掌握从数据预处理到模型预测的完整时序分析能力。

54

2025.12.04

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

393

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

574

2023.08.10

C++类型转换方式
C++类型转换方式

本专题整合了C++类型转换相关内容,想了解更多相关内容,请阅读专题下面的文章。

299

2025.07.15

数据分析的方法
数据分析的方法

数据分析的方法有:对比分析法,分组分析法,预测分析法,漏斗分析法,AB测试分析法,象限分析法,公式拆解法,可行域分析法,二八分析法,假设性分析法。php中文网为大家带来了数据分析的相关知识、以及相关文章等内容。

469

2023.07.04

数据分析方法有哪几种
数据分析方法有哪几种

数据分析方法有:1、描述性统计分析;2、探索性数据分析;3、假设检验;4、回归分析;5、聚类分析。本专题为大家提供数据分析方法的相关的文章、下载、课程内容,供大家免费下载体验。

280

2023.08.07

网站建设功能有哪些
网站建设功能有哪些

网站建设功能包括信息发布、内容管理、用户管理、搜索引擎优化、网站安全、数据分析、网站推广、响应式设计、社交媒体整合和电子商务等功能。这些功能可以帮助网站管理员创建一个具有吸引力、可用性和商业价值的网站,实现网站的目标。

733

2023.10.16

数据分析网站推荐
数据分析网站推荐

数据分析网站推荐:1、商业数据分析论坛;2、人大经济论坛-计量经济学与统计区;3、中国统计论坛;4、数据挖掘学习交流论坛;5、数据分析论坛;6、网站数据分析;7、数据分析;8、数据挖掘研究院;9、S-PLUS、R统计论坛。想了解更多数据分析的相关内容,可以阅读本专题下面的文章。

511

2024.03.13

菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

0

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.6万人学习

Django 教程
Django 教程

共28课时 | 3.4万人学习

Excel 教程
Excel 教程

共162课时 | 12.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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