给定一个看起来像这样的DataFrame
Index Time Val
1 2017-06-29 17:48 0
2 2017-06-29 17:49 0
3 2017-06-29 17:50 1
4 2017-06-29 17:51 2
5 2017-06-29 17:52 3
6 2017-06-29 17:53 0
7 2017-06-29 17:54 0
8 2017-06-29 17:55 0
9 2017-06-29 17:56 0
10 2017-06-29 17:57 0
如何将其拆分为两个列表的数据框,其中一个列表是val == 0
的块,一个是val > 0
(val < 0
所在的块没有发生)。但是,存在以下复杂情况。当val > 0
时,下一次val == 0
应该开始新的数据框,反之亦然。
因此,基于上面的数据框,第一个列表将包含两个数据帧:一个包含索引1-2,另一个包含索引6-9。第二个列表应包含一个索引3-5的数据帧。
我知道我可以通过执行val > 0
删除df[df.val == 0]
行,这将给出下面的数据框,但由于索引2和6之间的中断,我需要它们在不同的数据帧中。
Index Time Val
1 2017-06-29 17:48 0
2 2017-06-29 17:49 0
6 2017-06-29 17:53 0
7 2017-06-29 17:54 0
8 2017-06-29 17:55 0
9 2017-06-29 17:56 0
10 2017-06-29 17:57 0
N.B。这需要扩展到大数据帧(数百万行),因此需要速度。遍历每一行并寻找索引(或时间戳)的中断是不可取的。
答案 0 :(得分:1)
我无法保证以下内容会快速运行,但它应该会让你走得很远。这背后的想法是在run-length encoding
列上使用所谓的Val
生成一个新列,通过该列对数据帧进行分组。以下应该是一个不错的开始:
import pandas as pd
from pandas import Timestamp
from itertools import groupby
from functools import reduce
d = {'Time': [Timestamp('2017-06-29 17:48:00'),
Timestamp('2017-06-29 17:49:00'),
Timestamp('2017-06-29 17:50:00'),
Timestamp('2017-06-29 17:51:00'),
Timestamp('2017-06-29 17:52:00'),
Timestamp('2017-06-29 17:53:00'),
Timestamp('2017-06-29 17:54:00'),
Timestamp('2017-06-29 17:55:00'),
Timestamp('2017-06-29 17:56:00'),
Timestamp('2017-06-29 17:57:00')],
'Val': [0, 0, 1, 2, 3, 0, 0, 0, 0, 0]}
df = pd.DataFrame(d)
df['grouper'] = reduce(list.__add__, ([x]*len(list(y[1])) for x, y in enumerate(groupby(df.Val, key=lambda x: x > 0))))
bins = [[], []]
for _, frame in df.groupby('grouper'):
if (frame.Val == 0).all():
bins[0].append(frame.iloc[:, :-1])
else:
bins[1].append(frame.iloc[:, :-1])
print(bins)
应该产生以下列表:
# [[ Time Val
# 0 2017-06-29 17:48:00 0
# 1 2017-06-29 17:49:00 0, Time Val
# 5 2017-06-29 17:53:00 0
# 6 2017-06-29 17:54:00 0
# 7 2017-06-29 17:55:00 0
# 8 2017-06-29 17:56:00 0
# 9 2017-06-29 17:57:00 0], [ Time Val
# 2 2017-06-29 17:50:00 1
# 3 2017-06-29 17:51:00 2
# 4 2017-06-29 17:52:00 3]]
这里的想法是您在run-length encoding
列上应用Val
,这基本上意味着 您计算相等值的运行长度 。此过程的输出保存在名为grouper
的新列中。此列用于对初始数据帧进行分组。分组完成后,您可以继续将bins
列表中的单独数据框放在for-loop
上。
虽然我无法保证速度,但我相信这个想法可以非常轻松地为您提供所需的输出。您可以尝试使用run-length encoding
实现numpy
想法以获得一点速度。
如上所述,当groupby(df.Val, key=lambda x: x > 0)
包含空值时调用df.Val
,则不满足条件,因为NaN > 0
应返回False。在这种情况下,分组变得有缺陷,导致意外的输出。由于目标是区分等于0
的值和不等于key
的值,因此您可以在使用groupby(df.Val, key=lambda x: x == 0)
进行分组时更改传递给==
参数的函数。以下几乎与上述内容相同,唯一的例外是>
而不是d = {'Time': [Timestamp('2017-06-29 17:48:00'),
Timestamp('2017-06-29 17:49:00'),
Timestamp('2017-06-29 17:50:00'),
Timestamp('2017-06-29 17:51:00'),
Timestamp('2017-06-29 17:52:00'),
Timestamp('2017-06-29 17:53:00'),
Timestamp('2017-06-29 17:54:00'),
Timestamp('2017-06-29 17:55:00'),
Timestamp('2017-06-29 17:56:00'),
Timestamp('2017-06-29 17:57:00'),
Timestamp('2017-06-29 17:58:00'),
Timestamp('2017-06-29 17:59:00')],
'Val': [0, 0, 1, 2, 3, 0, None, 0, 0, 0, 0, None]}
df = pd.DataFrame(d)
df['grouper'] = reduce(list.__add__, ([x]*len(list(y[1])) for x, y in enumerate(groupby(df.Val, key=lambda x: x == 0))))
bins = [[], []]
for _, frame in df.groupby('grouper'):
if (frame.Val == 0).all():
bins[0].append(frame.iloc[:, :-1])
else:
bins[1].append(frame.iloc[:, :-1])
# [[ Time Val
# 0 2017-06-29 17:48:00 0.0
# 1 2017-06-29 17:49:00 0.0, Time Val
# 5 2017-06-29 17:53:00 0.0, Time Val
# 7 2017-06-29 17:55:00 0.0
# 8 2017-06-29 17:56:00 0.0
# 9 2017-06-29 17:57:00 0.0
# 10 2017-06-29 17:58:00 0.0], [ Time Val
# 2 2017-06-29 17:50:00 1.0
# 3 2017-06-29 17:51:00 2.0
# 4 2017-06-29 17:52:00 3.0, Time Val
# 6 2017-06-29 17:54:00 NaN, Time Val
# 11 2017-06-29 17:59:00 NaN]]
:
@ViewChild('myForm') myForm;
我希望这会有所帮助。