如何在Pandas中按特定条件将Result行切片为多个子DataFrame?
Pandas分割DataFrame问题解决
问题描述
需要将Pandas DataFrame中Step列为"Result"的行,以Point列值为"P1"且X_Y列值为"X"的位置作为起始点,分割为多个子DataFrame并存入list_of_dfs列表。尝试定位所有"P1"的索引后用列表推导式切片,但得到的列表包含两个空DataFrame,寻求解决方法。
用户原代码
import pandas as pd df = pd.DataFrame( { "Step": ( "1", "1", "1", "1", "1", "2", "2", "2", "2", "2", "Result", "Result", "Result", "Result", "Result", "1", "1", "1", "1", "1", "2", "2", "2", "2", "2", "Result", "Result", "Result", "Result", "Result" ), "Point": ( "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", ), "X_Y": ( "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", ), "Value A": ( 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, ), "Value B": ( 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, ), } ) dff = df.loc[df["Step"] == "Result"] value = "P1" tuple_of_positions = list() result = dff.isin([value]) seriesObj = result.any() columnNames = list(seriesObj[seriesObj == True].index) for col in columnNames: rows = list(result[col][result[col] == True].index) for row in rows: tuple_of_positions.append((row, col)) length_of_one_df = (len(dff["Point"].unique().tolist()) * 2 ) - 1 list_of_dfs = [dff.iloc[x : x + length_of_one_df] for x in rows] print(list_of_dfs)
问题分析
原代码存在两个核心问题:
- 最终切片用的
rows变量是循环最后一次赋值的结果,并非所有符合Point="P1"且X_Y="X"的索引位置; - 使用
iloc时传入了原DataFrame的索引标签,但iloc需要的是相对行号,原索引值超出dff的行范围后,就会产生空DataFrame。
解决方法
修正后的代码
import pandas as pd df = pd.DataFrame( { "Step": ( "1", "1", "1", "1", "1", "2", "2", "2", "2", "2", "Result", "Result", "Result", "Result", "Result", "1", "1", "1", "1", "1", "2", "2", "2", "2", "2", "Result", "Result", "Result", "Result", "Result" ), "Point": ( "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", "P1", "P2", "P2", "P3", "P3", ), "X_Y": ( "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", "X", "X", "Y", "X", "Y", ), "Value A": ( 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, ), "Value B": ( 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, 70, 68, 66.75, 68.08, 66.72, ), } ) # 筛选Step为Result的行 dff = df.loc[df["Step"] == "Result"] # 精准筛选符合条件的起始行,并获取其在dff中的相对行号 start_mask = (dff["Point"] == "P1") & (dff["X_Y"] == "X") start_positions = list(dff[start_mask].index.get_indexer(dff.index)) # 每个子DataFrame的长度,根据数据结构固定为5 length_of_one_df = 5 # 生成子DataFrame列表 list_of_dfs = [dff.iloc[x:x+length_of_one_df] for x in start_positions] # 验证结果 for idx, sub_df in enumerate(list_of_dfs): print(f"子DataFrame {idx+1}:") print(sub_df) print("-"*30)
关键修正点
- 精准筛选起始行:用
(dff["Point"] == "P1") & (dff["X_Y"] == "X")同时满足两个条件,避免误选其他含P1的行; - 获取相对行号:通过
index.get_indexer(dff.index)将原索引标签转换为dff内部的相对行号,确保iloc切片时使用正确的位置; - 正确切片:从每个起始行号开始,取连续5行(对应一组完整的P1-P3的X/Y数据),得到两个非空的子DataFrame。
内容的提问来源于stack exchange,提问作者Bakira
相关产品推荐
相关产品推荐

