You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将循环分块的复杂Pandas DataFrame转换为长格式?

解决Excel分块DataFrame转长格式问题

先模拟可复现的示例数据

先构造一个简化版的分块数据,对应2个小时块(Hour 1和Hour 2),每个块8行,列包含Hour标识和BZ项(FI、NO2):

import pandas as pd
import numpy as np

# 构造模拟数据
data = [
    # Hour 1块
    ['Hour 1', 'FI', 'NO2'],
    ['D1', np.nan, np.nan],
    ['ND', np.nan, np.nan],
    ['2024-05-20', np.nan, np.nan],
    [np.nan, 12.3, 45.6],
    [np.nan, 13.1, 46.2],
    [np.nan, 12.8, 45.9],
    [np.nan, 13.5, 46.5],
    # Hour 2块
    ['Hour 2', 'FI', 'NO2'],
    ['D2', np.nan, np.nan],
    ['Selected', np.nan, np.nan],
    ['2024-05-20', np.nan, np.nan],
    [np.nan, 22.1, 55.3],
    [np.nan, 22.5, 55.7],
    [np.nan, 22.3, 55.5],
    [np.nan, 22.7, 55.9]
]

df = pd.DataFrame(data)
print("原始分块DataFrame:")
print(df)

核心处理步骤

因为数据是每8行一个小时块,且元数据(Horizon、type、Day)都在块内的特定行,不能直接用pd.melt(),需要先拆分块提取元数据,再单独重塑每个块:

1. 按8行拆分所有小时块

# 按每8行拆分,得到每个小时块的列表
block_size = 8
blocks = [df.iloc[i:i+block_size] for i in range(0, len(df), block_size)]

2. 处理单个块,提取元数据并转长格式

定义一个函数处理每个块:

def process_block(block):
    # 提取小时信息:从块首行第一列提取小时数(比如'Hour 1' -> 1)
    hour = int(block.iloc[0, 0].split()[-1])
    # 提取Horizon:块的第2行第一列(索引1)
    horizon = block.iloc[1, 0]
    # 提取type:块的第3行第一列(索引2)
    type_val = block.iloc[2, 0]
    # 提取Day:块的第4行第一列(索引3)
    day = block.iloc[3, 0]
    
    # 提取数值行:块的第5到第8行(索引4到7),以及BZ列(索引1到末尾)
    value_rows = block.iloc[4:, 1:]
    # 设置BZ列为列名
    value_rows.columns = block.iloc[0, 1:].tolist()
    
    # 转长格式:把BZ列转成行,对应Value
    melted = value_rows.melt(var_name='BZ', value_name='Value').dropna(subset=['Value'])
    
    # 添加元数据列
    melted['Horizon (D1 or D2)'] = horizon
    melted['type'] = type_val
    melted['Day'] = day
    # 生成Datetime:Day + Hour(假设小时是整点)
    melted['Datetime'] = pd.to_datetime(melted['Day']) + pd.Timedelta(hours=hour)
    
    # 调整列顺序为要求的格式
    return melted[['Datetime', 'BZ', 'type', 'Horizon (D1 or D2)', 'Value', 'Day']]

3. 合并所有块的结果

# 处理所有块并合并
final_df = pd.concat([process_block(block) for block in blocks], ignore_index=True)
print("\n转换后的长格式DataFrame:")
print(final_df)

输出结果说明

转换后的DataFrame完全符合要求的列结构:

  • Datetime:自动拼接日期和小时生成时间戳
  • BZ:对应原始的FI、NO2等标识
  • type:提取块内的ND/Selected
  • Horizon (D1 or D2):提取块内的D1/D2
  • Value:所有数值数据
  • Day:原始的日期信息

关键要点

  • 分块处理是核心:因为数据是按固定行数循环的,先拆分才能单独提取每个小时的元数据
  • 元数据提取:每个块的第2-4行分别对应Horizon、type、Day,需要单独提取后合并到数值行中
  • 重塑时机:先提取数值部分再用melt(),而不是直接对整个大DataFrame操作,避免元数据和数值混在一起导致的错误

内容的提问来源于stack exchange,提问作者Tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 09:35:29