如何基于连续索引拆分数据帧?

时间:2019-05-22 12:56:03

标签: python pandas dataframe

我有一个具有不连续索引的数据帧“工作”,这里是一个示例:

Index Column1 Column2
4464  10.5    12.7
4465  11.3    12.8
4466  10.3    22.8
5123  11.3    21.8
5124  10.6    22.4
5323  18.6    23.5

我需要从此数据框中提取仅包含索引连续的行的新数据框,因此在这种情况下,我的目标是获取

DF_1.index=[4464,4465,4466]
DF_2.index=[5123,5124]
DF_3.index=[5323]

维护所有列。

有人可以帮助我吗?谢谢!

4 个答案:

答案 0 :(得分:5)

groupby

您可以使用以下方法制作完美的“连续”数组

np.arange(10)

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

如果我要从单调增加的索引中减去此值,则只有那些“连续”的索引成员才会显示为相等。这是建立分组依据的聪明方法。

list_of_df = [d for _, d in df.groupby(df.index - np.arange(len(df)))]

打印每一个以证明这一点

print(*list_of_df, sep='\n\n')

       Column1  Column2
Index                  
4464      10.5     12.7
4465      11.3     12.8
4466      10.3     22.8

       Column1  Column2
Index                  
5123      11.3     21.8
5124      10.6     22.4

       Column1  Column2
Index                  
5323      18.6     23.5

np.split

您可以使用np.flatnonzero来确定差异不等于1的地方,并避免使用cumsumgroupby

list_of_df = np.split(df, np.flatnonzero(np.diff(df.index) != 1) + 1)

证明

print(*list_of_df, sep='\n\n')

       Column1  Column2
Index                  
4464      10.5     12.7
4465      11.3     12.8
4466      10.3     22.8

       Column1  Column2
Index                  
5123      11.3     21.8
5124      10.6     22.4

       Column1  Column2
Index                  
5323      18.6     23.5

答案 1 :(得分:4)

这里是替代方法:

grouper = (~(pd.Series(df.index).diff() == 1)).cumsum().values  
dfs = [dfx for _ , dfx in df.groupby(grouper)]

我们使用这样一个事实,即连续差1等于一个序列(diff == 1)。

完整示例:

import pandas as pd

data = '''\
Index Column1 Column2
4464  10.5    12.7
4465  11.3    12.8
4466  10.3    22.8
5123  11.3    21.8
5124  10.6    22.4
5323  18.6    23.5
'''

fileobj = pd.compat.StringIO(data)
df = pd.read_csv(fileobj, sep='\s+', index_col='Index')

non_sequence = pd.Series(df.index).diff() != 1
grouper = non_sequence.cumsum().values
dfs = [dfx for _ , dfx in df.groupby(grouper)]

print(dfs[0])

#       Column1  Column2
#Index                  
#4464      10.5     12.7
#4465      11.3     12.8
#4466      10.3     22.8

另一种看待它的方式是,我们寻找groupby的非序列,可能更易读:

non_sequence = pd.Series(df.index).diff() != 1
grouper = non_sequence.cumsum().values
dfs = [dfx for _ , dfx in df.groupby(grouper)]

答案 2 :(得分:0)

也许有一种更优雅的方式将其写下来,但这对我有用:

previous_index = df.index[0]
groups = {}
for x in df.index:
    if (x-previous_index) ==1 : 
        groups[max(groups.keys())].append(x)
    else:
        groups[len(groups.keys())]=[x]
    previous_index = x

output_dfs = []
for key, val in groups.items():
    print(key, val)
    output_dfs.append(df[df.index.isin(val)])

您的数据帧将存储在output_dfs

output_dfs[0].index
  

[4464,4465,4466]

答案 3 :(得分:0)

您可以使用exec创建多个数据框并获得预期的结果:

df = pd.DataFrame({'Column1' : [10.5,11.3,10.3,11.3,10.6,18.6], 'Column2' : [10.5,11.3,10.3,11.3,10.6,18.6]})
df.index = [4464, 4465, 4466, 5123, 5124, 5323]

prev_index = df.index[0]
df_1 = pd.DataFrame(df.iloc[0]).T
num_df = 1
for i in df.index[1:]:
    if i == prev_index+1:
        exec('df_{} = df_{}.append(df.loc[{}])'.format(num_df, num_df, i))
    else :
        num_df += 1
        exec('df_{} = pd.DataFrame(df.loc[{}]).T'.format(num_df, i))
    prev_index = i