gpt4 book ai didi

python - 有条件地填充 pandas groupby 对象中元素的有效方法(可能通过应用函数)

转载 作者:太空宇宙 更新时间:2023-11-04 09:58:14 26 4
gpt4 key购买 nike

我在尝试将函数应用于从具有大约 150,000 行的数据帧派生的 groupby 对象时遇到性能问题。

为简单起见,让我们处理虚拟数据框 a

arrays = [['bar', 'bar','bar', 'baz', 'baz', 'foo', 'foo', 'foo', 'qux', 'qux'],
['one', 'one','two', 'one', 'two', 'one', 'two', 'two', 'one', 'two']]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
a = pd.DataFrame(np.random.random((10,)), index = index)
a[1] = pd.date_range('2017-07-02', periods=10, freq='5min')


a
Out[24]:
0 1
first second
bar one 0.821371 2017-07-02 00:00:00
one 0.312364 2017-07-02 00:05:00
two 0.104821 2017-07-02 00:10:00
baz one 0.839370 2017-07-02 00:15:00
two 0.307262 2017-07-02 00:20:00
foo one 0.719300 2017-07-02 00:25:00
two 0.371118 2017-07-02 00:30:00
two 0.765483 2017-07-02 00:35:00
qux one 0.794236 2017-07-02 00:40:00
two 0.571231 2017-07-02 00:45:00

我想根据此处描述的逻辑有条件地填充每个 first-second 组中第 0 列的底部元素功能

def myfunc(g):


if( len(g) >= 2): # if each group's length is greater than or equal to 2, then:

if ((g.loc[g.index[-1], 0] > 0.5)): # If the last element of the 0th column of the group > 0.5, then:

time_gap = g.loc[g.index[-1], 1] - g.loc[g.index[-2], 1] # Find the time difference between the last two records in 1st column

g.loc[g.index[-1], 0] = time_gap # and assign it to the last element in the 0th column of that group

else:
g.loc[g.index[-1], 0] = 'ELSE' # Assign ELSE to the last element of the 0th column of the group


return g

应用这个函数产生,

a.reset_index().groupby(['first', 'second']).apply(myfunc)
Out[23]:
first second 0 1
0 bar one 0.821371 2017-07-02 00:00:00
1 bar one ELSE 2017-07-02 00:05:00 correct
2 bar two 0.104821 2017-07-02 00:10:00
3 baz one 0.83937 2017-07-02 00:15:00
4 baz two 0.307262 2017-07-02 00:20:00
5 foo one 0.7193 2017-07-02 00:25:00
6 foo two 0.371118 2017-07-02 00:30:00
7 foo two 0 days 00:05:00 2017-07-02 00:35:00 correct
8 qux one 0.794236 2017-07-02 00:40:00
9 qux two 0.571231 2017-07-02 00:45:00

上面的结果正是我想要的。问题是,当应用于我有大约 150,000 行的数据帧时,这种方法卡住了我的 16GB/i5-6200U CPU @ 2.3GHz 计算机。

在(可能)我需要编写函数的地方有条件地填充此类元素的最有效方法是什么?

注意:我在 Windows 10 上的 jupyter notebook 中运行了它 - 如果这很重要的话

最佳答案

这里有几个问题。

  1. 您正在通过应用编辑组内的数据框。这注定要进行大量调试。
  2. 当您在 groupby 中使用 apply 时,您会为每个组创建一个新的数据框。我们可以通过操纵组的索引来提高性能。
  3. 您无需重置索引即可按索引级别分组

首先,请制作一份 a 的副本,以防万一在翻译中丢失某些内容,我不想让你搞砸 a...。

a_ = a.copy()

好的,让它更快

g = a.groupby(level=['first', 'second'])

我将大量使用 get_valueset_value,其中 takeable=Truetakeable 选项允许我使用其他参数作为位置引用。因此,我想确保我的位置正确。

j0 = a.columns.get_loc(0)
j1 = a.columns.get_loc(1)

方便的是,g 有一个 indices 属性,它告诉我每个命名组的所有行的位置。我将创建一个名称和索引的字典,使用推导式通过长度为 2 或更长的第一个障碍。

g_ = {n: i for n, i in g.indices.items() if i.size > 1}

您正在将不同种类的东西放入 0 列中,因为我要使用 set_value,所以我最好将该列转换为 object 提前。

a[0] = a[0].astype(object)

现在,我可以遍历通过上述长度障碍的组。

for n, i in g_.items():
i0, i1 = i[-2:]
cond = a.get_value(i1, j0, takeable=True) > 0.5
if cond:
tgap = a.get_value(i1, j1, takeable=True) - a.get_value(i0, j1, takeable=True)
a.set_value(i1, j0, tgap, takeable=True)
else:
a.set_value(i1, j0, 'ELSE', takeable=True)

一起

g = a.groupby(level=['first', 'second'])

j0 = a.columns.get_loc(0)
j1 = a.columns.get_loc(1)
g_ = {n: i for n, i in g.indices.items() if i.size > 1}

a[0] = a[0].astype(object)

for n, i in g_.items():
i0, i1 = i[-2:]
cond = a.get_value(i1, j0, takeable=True) > 0.5
if cond:
tgap = a.get_value(i1, j1, takeable=True) - a.get_value(i0, j1, takeable=True)
a.set_value(i1, j0, tgap, takeable=True)
else:
a.set_value(i1, j0, 'ELSE', takeable=True)

时间

%timeit a.reset_index().groupby(['first', 'second']).apply(myfunc)
100 loops, best of 3: 7.14 ms per loop

%%timeit
a = b.copy()
g = a.groupby(level=['first', 'second'])

j0 = a.columns.get_loc(0)
j1 = a.columns.get_loc(1)
g_ = {n: i for n, i in g.indices.items() if i.size > 1}

a[0] = a[0].astype(object)

for n, i in g_.items():
i0, i1 = i[-2:]
cond = a.get_value(i1, j0, takeable=True) > 0.5
if cond:
tgap = a.get_value(i1, j1, takeable=True) - a.get_value(i0, j1, takeable=True)
a.set_value(i1, j0, tgap, takeable=True)
else:
a.set_value(i1, j0, 'ELSE', takeable=True)

1000 loops, best of 3: 1.01 ms per loop

关于python - 有条件地填充 pandas groupby 对象中元素的有效方法(可能通过应用函数),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44954514/

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