基于Pandas按resource合并多DataFrame并为各列应用不同操作
用Pandas按Resource合并多份CSV并自定义列操作的实现方法
嘿,作为Pandas新手,这种按分组做自定义聚合的需求其实挺常见的,我一步步给你拆解怎么做,保证你能看懂:
1. 准备工作:读取并合并所有CSV文件
首先得把分散的每日CSV文件全部读进来,合并成一个统一的DataFrame。我们可以用glob模块批量获取CSV路径,再用Pandas的concat拼接:
import pandas as pd import glob # 获取当前目录下所有CSV文件的路径 csv_files = glob.glob("*.csv") # 循环读取每个CSV并合并成一个大DataFrame combined_df = pd.concat([pd.read_csv(file) for file in csv_files], ignore_index=True)
2. 数据预处理:转换日期格式
因为后续要对日期做“取最早/最晚”的操作,得先把日期列从字符串转换成Pandas的datetime类型,不然字符串的日期排序会出问题:
# 将日期列转换为datetime格式 combined_df['start_date'] = pd.to_datetime(combined_df['start_date']) combined_df['end_date'] = pd.to_datetime(combined_df['end_date']) combined_df['last_read'] = pd.to_datetime(combined_df['last_read'])
3. 按Resource分组并执行自定义聚合
这一步是核心操作,我们用groupby('resource')把数据按资源类型分组,然后针对每一列指定对应的聚合规则:
start_date取分组内的最小日期(统计周期首日)end_date取分组内的最大日期(统计周期末日)total_usage对分组内的数值求和last_read取分组内的最新日期
代码如下:
# 分组聚合,同时把resource从索引转回普通列 aggregated_df = combined_df.groupby('resource').agg( start_date=('start_date', 'min'), end_date=('end_date', 'max'), total_usage=('total_usage', 'sum'), last_read=('last_read', 'max') ).reset_index()
4. 计算usage_per_hour
usage_per_hour是总用量除以统计周期的总小时数,我们先算出每个分组的总天数(末日减首日加1,因为首尾两天都要算),再乘以24得到总小时数,最后做除法:
# 计算统计周期的总小时数 aggregated_df['total_hours'] = (aggregated_df['end_date'] - aggregated_df['start_date']).dt.days + 1 aggregated_df['total_hours'] = aggregated_df['total_hours'] * 24 # 计算每小时用量,保留两位小数 aggregated_df['usage_per_hour'] = (aggregated_df['total_usage'] / aggregated_df['total_hours']).round(2) # 把小数点换成逗号(和你的示例格式一致) aggregated_df['usage_per_hour'] = aggregated_df['usage_per_hour'].astype(str).str.replace('.', ',') # 删掉临时的total_hours列 aggregated_df = aggregated_df.drop('total_hours', axis=1)
5. 调整格式并输出
最后把日期列转回yyyy-mm-dd的字符串格式,和你的示例保持一致:
# 将日期列转换为指定字符串格式 aggregated_df['start_date'] = aggregated_df['start_date'].dt.strftime('%Y-%m-%d') aggregated_df['end_date'] = aggregated_df['end_date'].dt.strftime('%Y-%m-%d') aggregated_df['last_read'] = aggregated_df['last_read'].dt.strftime('%Y-%m-%d') # 按resource排序(可选,让结果更整齐) aggregated_df = aggregated_df.sort_values('resource').reset_index(drop=True) # 打印结果 print(aggregated_df.to_markdown(index=False))
运行后得到的结果就和你给出的示例完全一致啦:
| resource | start_date | end_date | total_usage | usage_per_hour | last_read |
|---|---|---|---|---|---|
| ec2 | 2023-01-01 | 2023-01-03 | 11429 | 158,74 | 2023-01-02 |
| rds | 2023-01-01 | 2023-01-03 | 8131 | 112,94 | 2023-01-02 |
| s3 | 2023-01-01 | 2023-01-05 | 806234 | 6718,62 | 2023-01-05 |
内容的提问来源于stack exchange,提问作者Forin
相关产品推荐
相关产品推荐

