如何基于已有DataFrame的指定列非空值拆分生成新DataFrame?
实现方法:使用Pandas重塑与合并数据
当然有办法实现这个需求!下面我会给出两种可行的方案,分别适合小数据集和大数据集的场景:
方案一:直观循环法(适合小数据集)
这种方法逻辑清晰,容易理解,适合数据量不大的情况:
首先,我们先创建示例DataFrame(你可以直接替换成自己的数据集):
import pandas as pd import numpy as np # 构造示例数据 data = { 'timestamp': ['2022-05-09 11:28:00', '2022-05-09 11:28:01', '2022-05-09 11:28:02', '2022-05-09 11:28:03'], 'ID': [3.0, 3.0, 5.0, 5.0], 'val1': [-11, -7, -8, -7], 'sum': [100, 0.5, 50, np.nan], '3.0': [np.nan, np.nan, -35, 30], '5.0': [np.nan, np.nan, np.nan, np.nan], '7.0': [-45, -9, -20, np.nan], '9.0': [-67, np.nan, np.nan, np.nan], 'sum_3.0': [80, 70, 12, 67], 'sum_5.0': [123, 45, 23, 87], 'sum_7.0': [0.98, 0.23, 0.0, 0.90], 'sum_9.0': [345, 23, 14, 13] } df = pd.DataFrame(data)
接下来分三步处理:
- 保留原行数据:提取需求中要求保留的基础列
# 提取原行的基础列 original_rows = df[['timestamp', 'ID', 'val1', 'sum']].copy()
- 生成新增行数据:遍历每一行,检查目标列的非NaN值,生成对应新行
# 定义需要处理的列对:(值列, sum对应列) column_pairs = [('3.0', 'sum_3.0'), ('5.0', 'sum_5.0'), ('7.0', 'sum_7.0'), ('9.0', 'sum_9.0')] new_rows = [] for idx, row in df.iterrows(): current_timestamp = row['timestamp'] # 遍历每个列对,检查是否有非NaN值 for val_col, sum_col in column_pairs: val = row[val_col] sum_val = row[sum_col] if not pd.isna(val): # 符合条件则添加新行 new_rows.append({ 'timestamp': current_timestamp, 'ID': float(val_col), # 将列名转为数字ID 'val1': val, 'sum': sum_val }) # 把新行转为DataFrame new_rows_df = pd.DataFrame(new_rows)
- 合并数据得到最终结果
# 合并原行和新行,重置索引 final_df = pd.concat([original_rows, new_rows_df], ignore_index=True)
方案二:向量化重塑法(适合大数据集)
如果你的数据集很大,循环会比较慢,推荐使用Pandas的melt函数进行向量化操作,效率更高:
# 步骤1:提取原行数据(和方案一相同) original_rows = df[['timestamp', 'ID', 'val1', 'sum']].copy() # 步骤2:将值列转为长格式 melted_vals = df.melt( id_vars=['timestamp'], value_vars=['3.0', '5.0', '7.0', '9.0'], var_name='ID', value_name='val1' ) # 步骤3:将sum列转为长格式,并匹配对应ID melted_sums = df.melt( id_vars=['timestamp'], value_vars=['sum_3.0', 'sum_5.0', 'sum_7.0', 'sum_9.0'], var_name='sum_col', value_name='sum' ) # 去掉sum_前缀,得到对应的ID melted_sums['ID'] = melted_sums['sum_col'].str.replace('sum_', '') # 步骤4:合并值和sum的长格式数据,过滤NaN值 expanded_df = pd.merge(melted_vals, melted_sums, on=['timestamp', 'ID'], how='left') expanded_df = expanded_df.dropna(subset=['val1']).drop(columns=['sum_col']) # 将ID转为float类型 expanded_df['ID'] = expanded_df['ID'].astype(float) # 步骤5:合并原行和展开后的行 final_df = pd.concat([original_rows, expanded_df], ignore_index=True)
运行以上任意一种方案,你都会得到和期望完全一致的DataFrame。
内容的提问来源于stack exchange,提问作者EngGu
相关产品推荐
相关产品推荐

