Python 按两个重复值拆分数据帧

Python 按两个重复值拆分数据帧,python,pandas,numpy,Python,Pandas,Numpy,我有一个描述个人状态的数据框: df = pd.DataFrame({'A': [1, 2, 3, 4, 5, 6, 7, 8, 3], 'B': [6, 7, 8, 9, 10, 23, 11, 12, 13], 'C': ['start', 'running', 'running', 'end', 'running', 'start', 'running', 'resting', 'end']}) 这个数据框记录了

我有一个描述个人状态的数据框:

df = pd.DataFrame({'A': [1, 2, 3, 4, 5, 6, 7, 8, 3], 
                  'B': [6, 7, 8, 9, 10, 23, 11, 12, 13], 
                  'C': ['start', 'running', 'running', 'end', 'running', 'start', 'running', 'resting', 'end']})
这个数据框记录了这个人的两次旅行。我想根据C列“开始”和“结束”的值将其拆分。C列中的其他值无关紧要

我可以用以下代码划分数据帧:

x=[]
y=[]

for i in range(len(df)):
    if df['C'][i]=='start':
        x.append(i)
    elif df['C'][i]=='end':
        y.append(i)

for i, j in zip(x, y):
    new_df = df.iloc[i:j+1,:]
    print(new_df)

然而,由于我有一个相当大的数据帧,我想知道有没有更有效的方法来无循环地划分它。

我会使用

方法1

start = df['C'].eq('start')
dfs = dict(df.loc[(start.add(df['C'].shift().eq('end')).cumsum()%2).eq(1)]
             .groupby(start.cumsum())
             .__iter__())

#{1:    A  B        C
# 0  1  6    start
# 1  2  7  running
# 2  3  8  running
# 3  4  9      end, 2:    A   B        C
# 5  6  23    start
# 6  7  11  running
# 7  8  12  resting
# 8  3  13      end}
方法2

start = df['C'].eq('start')
dfs = dict(df.loc[start.where(start)
                       .groupby(df['C'].shift()
                                       .eq('end')
                                       .cumsum())
                       .ffill().notna()]
             .groupby(start.cumsum())
             .__iter__())

#{1:    A  B        C
# 0  1  6    start
# 1  2  7  running
# 2  3  8  running
# 3  4  9      end, 2:    A   B        C
# 5  6  23    start
# 6  7  11  running
# 7  8  12  resting
# 8  3  13      end}
start.where(start)
0    1.0
1    NaN
2    NaN
3    NaN
4    NaN
5    1.0
6    NaN
7    NaN
8    NaN
Name: C, dtype: float64

df['C'].shift().eq('end').cumsum()


0    0
1    0
2    0
3    0
4    1
5    1
6    1
7    1
8    1
Name: C, dtype: int64
访问数据帧

print(dfs[1])
   A  B        C
0  1  6    start
1  2  7  running
2  3  8  running
3  4  9      end

print(dfs[2])
   A   B        C
5  6  23    start
6  7  11  running
7  8  12  resting
8  3  13      end

我们可以使用


详细说明方法2

start = df['C'].eq('start')
dfs = dict(df.loc[start.where(start)
                       .groupby(df['C'].shift()
                                       .eq('end')
                                       .cumsum())
                       .ffill().notna()]
             .groupby(start.cumsum())
             .__iter__())

#{1:    A  B        C
# 0  1  6    start
# 1  2  7  running
# 2  3  8  running
# 3  4  9      end, 2:    A   B        C
# 5  6  23    start
# 6  7  11  running
# 7  8  12  resting
# 8  3  13      end}
start.where(start)
0    1.0
1    NaN
2    NaN
3    NaN
4    NaN
5    1.0
6    NaN
7    NaN
8    NaN
Name: C, dtype: float64

df['C'].shift().eq('end').cumsum()


0    0
1    0
2    0
3    0
4    1
5    1
6    1
7    1
8    1
Name: C, dtype: int64
如您所见,
第4行
位于组1内,使用时其值保持为
NaN
请尝试:

将numpy导入为np
df[“group”]=df.groupby(“C”).cumcount()
df.loc[df[“C”].ne(“开始”),“组”]=无
df[“组”]=np.where(np.logical_和(df[“C”].shift(1).eq(“结束”),df[“C”].ne(“开始”),-1,df[“组”])
df[“组”]=df[“组”].ffill()
dfs=[df.loc[df[“group”].eq(grp)],用于df.groupby(“group”).groups中的grp]
产出:

#dfs[0]
A B C群
4 5 10运行-1.0
#dfs[1]
A B C群
01 6开始0.0
1 2 7运行0.0
2 3 8运行0.0
3 4 9结束0.0
#dfs[2]
A B C群
5 6 23开始1.0
6711运行1.0
7 8 12 1.0
8 3 13结束1.0

使用
stru extract
cumsum
groupby
将结果保存在字典中

df_dict = {}
counter =0 

for group, data in df.assign(
    g=df["C"].str.extract("(A|C)").bfill().apply(lambda x: x.ne("C")).cumsum()
).groupby("g"):
    counter += 1
    df_dict[counter] = data.drop('g',axis=1)


根据注释,起始数据帧:

df = pd.DataFrame({'A': [1, 2, 3, 4, 5, 6, 7, 8, 3],
                  'B': [6, 7, 8, 9, 10, 23, 11, 12, 13],
                  'C': ['start', 'running', 'running', 'end', 'running', 'start', 'running', 'resting', 'end']})
然后:

印刷品:

   A  B        C
0  1  6    start
1  2  7  running
2  3  8  running
3  4  9      end
   A   B        C
5  6  23    start
6  7  11  running
7  8  12  resting
8  3  13      end
您可以使用:

idx = zip(df[df['C'] == 'A'].index, df[df['C'] == 'C'].index)
dfs = [df.loc[i:j] for i, j in idx]  

我认为您可以使用这一行代码:

dfs = [ df[start:end+1] 
        for start, end in zip(df.index[df['C'] == 'start'], 
                              df.index[df['C'] == 'end'])]
输出:

dfs[0]

   A  B        C
0  1  6    start
1  2  7  running
2  3  8  running
3  4  9      end

dfs[1]

   A   B        C
5  6  23    start
6  7  11  running
7  8  12  resting
8  3  13      end

@不,我想分割数据帧。此处的数据帧应分为两个数据帧。对于它们中的每一个,列C以A开头,以A结尾C@PeiLi如果列
C
中的值是按顺序排列的,例如
“A”、“B”、“A”、“C”
,该怎么办。那么数据帧是如何划分的呢?@Andrej Kesely我的数据中的“a”后面必须有一个“C”,比如“开始”和“结束”。基于原始数据进行分割不是更有意义吗?因此,您将获得所需df数量的数据,而无需担心如何在单个df中执行。第4行在组中省略了吗?
dfs[0]

   A  B        C
0  1  6    start
1  2  7  running
2  3  8  running
3  4  9      end

dfs[1]

   A   B        C
5  6  23    start
6  7  11  running
7  8  12  resting
8  3  13      end