我有一个名为df
的Pandas DataFrame,其列名为“ step”,它只是一个增量计数器(1、2、3、4等):
step col1 col2
1 2 3
2 3 5
3 1 0
4 8 9
5 2 3
我正在从df
中选择一些感兴趣的行:
work_df = df[df[col1] < df[col2]]
step col1 col2
1 2 3
2 3 5
4 8 9
5 2 3
现在,我应该通过“ step”的连续性将work_df
拆分为一些sub_df(即,如果work_df['step'] == [1,2,3,7,8,9]
则[1,2,3]
属于sub_df_1
而[7,8,9]
属于sub_df_2
等),目前我是这样操作的:
for idx, row in work_df.iterrows():
if row['step'] > prev_step + 1:
if step_count > 1: #don't want to have df with only 1 row
interval_list.append({'step_count': step_count ... })
step_count = 0
else:
step_count += 1
prev_step = row['step']
然后我基于interval_list
的信息来构建新的sub_df。但是我不确定这是否是实现我真正需要的最佳方法:
sub_df1=
step col1 col2
1 2 3
2 3 5
sub_df2=
step col1 col2
4 8 9
5 2 3
是否有更好的方法通过列的连续性拆分DataFrame?
答案 0 :(得分:1)
您可以在此处按(df[col] != df[col].shift(1)+1).cumsum()
分组,也可以按@MarkWang says df['data'].diff().ne(1).cumsum()
分组。确实,如果我们使用您的样本数据:
>>> df
data
0 1
1 2
2 3
3 7
4 8
5 9
然后此表达式将产生:
>>> df['data'].diff().ne(1).cumsum()
0 1
1 1
2 1
3 2
4 2
5 2
Name: data, dtype: int64
因此我们可以在这些值上执行groupby
:
>>> list(df.groupby(df['data'].diff().ne(1).cumsum()))
[(1, data
0 1
1 2
2 3), (2, data
3 7
4 8
5 9)]
因此,我们这里有两组:[1,2,3]
和[7,8,9]
。因此,您可以在这里通过以下方式获得两个组:
>>> (__, sub_df_1), (__, sub_df_2) = df.groupby(df['data'].diff().ne(1).cumsum())
>>> sub_df_1
data
0 1
1 2
2 3
>>> sub_df_2
data
3 7
4 8
5 9
或您提供的第二个示例数据片段:
>>> (__, sub_df1), (__, sub_df2) = df2.groupby(df2['data'].diff().ne(1).cumsum())
>>> sub_df1
step col1 col2
0 1 2 3
1 2 3 5
>>> sub_df2
step col1 col2
2 4 8 9
3 5 2 3
例如,您可以在这里使用列表推导或itemgetter
来获取相应的组。例如:
>>> [g[1] for g in df2.groupby(df2['step'].diff().ne(1).cumsum())]
[ step col1 col2
0 1 2 3
1 2 3 5, step col1 col2
2 4 8 9
3 5 2 3]
您也可以使用1
删除长度为几的组:
>>> [g[1] for g in df2.groupby(df2['step'].diff().ne(1).cumsum()) if len(g[1]) > 1]
[ step col1 col2
0 1 2 3
1 2 3 5, step col1 col2
2 4 8 9
3 5 2 3]
因此,此列表包含两个子组。我强烈建议您按名称分配。是的,它是strictly speaking possible。但这是一种反模式,通常弊大于利。