高效简洁的GroupBy列传递

2024-06-28 20:40:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我想知道将讨厌的列传递给pandas.DataFrame.groupby结果的高效简洁的方法。我经常有一些列不想对其应用groupby操作,但我确实希望这些值传递给结果。下面是我尝试做的一个例子

import pandas as pd
import numpy as np
import random
import string

np.random.seed(43)
random.seed(43)

dates = pd.date_range("2015-01-01", "2017-01-02")
types = "AAABBCCCDDDDEEFFFFGG"
rtypes = list(types * len(dates)) 
rdates = dates.tolist() * len(types)

data = np.random.randn(len(rtypes))
info1 = [''.join(random.choice(string.ascii_uppercase) for _ in range(5)) 
         for i in range(len(rtypes))]
info2 = [random.randint(100,1000) for i in range(len(rtypes))]
df = pd.DataFrame({"date": rdates, "category": rtypes, "vals": data, 
                   "info1":info1, "info2": info2})
df = df.sort_values(["date", "category"]).reset_index(drop=True)

df.head()

  category       date  info1  info2      vals
0        A 2015-01-01  BJWYE    990  0.257400
1        A 2015-01-01  ISQES    475 -0.867570
2        A 2015-01-01  KDEKE    214  1.683595
3        B 2015-01-01  TFOXR    203  0.575879
4        B 2015-01-01  HKTNF    992 -0.399677

这里我想按categorydate分组,并对vals应用一些函数,但要传递info1info2列。你知道吗

可能的解决方案

这些是我找到的可能的解决方案,但它们都显得有些笨拙,性能也有很大的不同,这让我想知道是否可能有一个更有效或更简洁的解决方案。我在本例中应用了rank函数,但对每个组返回1个值、每个组返回所有值或每个组返回一些值的函数更感兴趣。

选项1

在索引中隐藏所有所需的传递列

%%timeit 

(df.set_index(["date", "category", "info1", "info2"])
 .groupby(axis=0, level=[0, 1]).rank().reset_index())

2.64 s ± 47.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

有结果的

sol1 = (df.set_index(["date", "category", "info1", "info2"])
        .groupby(axis=0, level=[0, 1]).rank().reset_index())
sol1.sort_values(["date", "category"]).head()

        date category  info1  info2  vals
0 2015-01-01        A  BJWYE    990   2.0
1 2015-01-01        A  ISQES    475   1.0
2 2015-01-01        A  KDEKE    214   3.0
3 2015-01-01        B  TFOXR    203   2.0
4 2015-01-01        B  HKTNF    992   1.0

选项2

删除列,稍后再将它们连接回来

%%timeit

pd.merge(
    df.groupby(by=["date", "category"])[["vals"]].rank(),
    df.drop("vals", axis=1),
    how="left",
    left_index=True,
    right_index=True,
)

1.73 s ± 180 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Tags: importdfdateindexlenrangerandompd
1条回答
网友
1楼 · 发布于 2024-06-28 20:40:27

我觉得你把事情搞得太复杂了。您可以只groupbyrankvals列。这将返回与原始pandas.Series长度相同的df,因此您可以将列设置为该值。你知道吗

df['vals'] = df.groupby(['date', 'category']).vals.rank()

  category       date  info1  info2  vals
0        A 2015-01-01  BJWYE    990   2.0
1        A 2015-01-01  ISQES    475   1.0
2        A 2015-01-01  KDEKE    214   3.0
3        B 2015-01-01  TFOXR    203   2.0
4        B 2015-01-01  HKTNF    992   1.0

相关问题 更多 >