gpt4 book ai didi

python - pandas DataFrame的条件分割

转载 作者:太空宇宙 更新时间:2023-11-03 15:03:53 27 4
gpt4 key购买 nike

给定一个如下所示的 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 所在的 block 其中一个是 val > 0 所在的 block ( val < 0 不会发生)。然而,存在以下复杂情况。当val > 0 ,下次val == 0应该开始一个新的数据框,反之亦然。

因此,根据上面的数据帧,第一个列表将包含两个数据帧:一个包含索引 1-2,另一个包含索引 6-9。第二个列表应包含索引 3-5 的一个数据帧。

我知道我可以去掉 val > 0df[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

注意这需要扩展到大型数据帧(数百万行),因此速度是理想的。遍历每一行并寻找索引(或时间戳)中的中断并不是可取的。

最佳答案

我不能保证以下内容会运行得很快,但它应该能让你走得很远。其背后的想法是在 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]]

这里的想法是,您在 Val 列上应用游程长度编码,这基本上意味着您计算的游程长度相同的值。此过程的输出保存在名为 grouper 的新列中。此列用于对初始数据框进行分组。分组完成后,您可以使用 for 循环 将单独的数据帧放入 bins 列表中。

虽然我不能保证速度,但我相信这个想法很容易让你得到你想要的输出。您可以尝试使用 numpy 实现游程编码的想法,以提高一点速度。

编辑:

如上所述,当 groupby(df.Val, key=lambda x: x > 0) 被调用而 df.Val 包含 null 值时,条件不成立满足,因为 NaN > 0 应该返回 False。在这种情况下,分组就会出错,导致意外的输出。由于目标是区分等于 0 的值和不等于 0 的值,因此您可以在使用 groupby(df 分组时更改传递给 key 参数的函数.Val, key=lambda x: x == 0)。下面的内容与上面的内容几乎相同,唯一的异常(exception)是 == 而不是 >:

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]]

我希望这会有所帮助。

关于python - pandas DataFrame的条件分割,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44831161/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com