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