在pandas中,当我对DataFrame进行求和时,如何获得一个DataFrame作为输出?

20

当我对一个 DataFrame 进行求和操作时,它会返回一个 Series:

In [1]: import pandas as pd
In [2]: df = pd.DataFrame([[1, 2, 3], [2, 3, 3]], columns=['a', 'b', 'c'])

In [3]: df
Out[3]: 
      a  b  c
   0  1  2  3
   1  2  3  3

   In [4]: s = df.sum()

   In [5]: type(s)
   Out[5]: pandas.core.series.Series

我知道可以通过这个 Series 构建一个新的 DataFrame。但是,有没有更多“pandasic”的方法呢?


1
我认为 pd.DataFrame({'my_sum': df.sum()}) 已经足够 Pandas 化了。这使您有可能给您的总和“命名”。 - eumiro
1
虽然不够简洁,但是pd.DataFrame(np.sum(df.values, axis=1), columns=['my_sum'])的速度明显更快... - root
1
+1 for pandastic,但我认为答案是否定的 :( - Andy Hayden
6个回答

13

我想说的是……"不",我认为没有直接的方法可以做到,pandas风格的方式(同时也是Pythonic的方式)是要明确表达:

pd.DataFrame(df.sum(), columns=['sum'])

或者更优美地,使用字典(请注意,这会复制总和数组):

pd.DataFrame({'sum': df.sum()})

正如 @root 所指出的那样,使用以下方式更快:

pd.DataFrame(np.sum(df.values, axis=0), columns=['sum'])

正如Python之禅所述:“实用性胜过纯粹性”,所以如果你在意时间的话,就使用它吧。

然而,或许最Pandastic(指使用Pandas库时最优雅的方式)的方法是直接使用Series! :)

.

以下是一些关于你的小例子的%timeit

In [11]: %timeit pd.DataFrame(df.sum(), columns=['sum'])
1000 loops, best of 3: 356 us per loop

In [12]: %timeit pd.DataFrame({'sum': df.sum()})
1000 loops, best of 3: 462 us per loop

In [13]: %timeit  pd.DataFrame(np.sum(df.values, axis=0), columns=['sum'])
1000 loops, best of 3: 205 us per loop

还有一个稍微大一点的:

In [21]: df = pd.DataFrame(np.random.randn(100000, 3), columns=list('abc'))

In [22]: %timeit pd.DataFrame(df.sum(), columns=['sum'])
100 loops, best of 3: 7.99 ms per loop

In [23]: %timeit pd.DataFrame({'sum': df.sum()})
100 loops, best of 3: 8.3 ms per loop

In [24]: %timeit  pd.DataFrame(np.sum(df.values, axis=0), columns=['sum'])
100 loops, best of 3: 2.47 ms per loop

1
啊,我们已经确定使用“熊猫精彩”的说法了吗?对我来说没问题(我也喜欢“熊猫棒极了”,但是没有“s”)。 - DSM
1
@DSM,“pandarrific”听起来有点太像“horrific”(可怕)了,而不是terrific(很棒)…… “pandastic”没有歧义,我认为我被吸引了! :) - Andy Hayden
Andy,谢谢您的回复。我暂时保持问题开放,等待其他可能的答案。如果没有其他答案,几天后会接受。 - waitingkuo

11

通常不仅需要将列的总和转换为数据框,还需要转置结果数据框。这里也有一种方法:

df.sum().to_frame().transpose()

你也可以为了简洁而直接写.T代替.transpose()df.sum().to_frame('sum').T - Arthur Khazbs

6
你可以使用agg进行像sum这样的简单操作,看看这有多紧凑:
df.agg(['sum'])

然而,这可能会带来显著的性能成本。当较短的执行时间比较短的代码行更重要时,请考虑其他解决方案。


1
不错。非常感谢。 - Bouncner
1
我真的很喜欢这种语法,但不幸的是,在我的使用场景中,它导致了严重的性能问题。我将df.any(axis=1)重写为df.agg(["any"], axis=1),在一个中等大小的数据框上运行几乎花费了一分钟的时间。切换回原来的写法后,运行时间恢复正常。我知道这只是个案证据,但或许可以帮助其他人避免一些困惑。 - lunguini
1
我非常喜欢这种语法,但不幸的是,在我的使用情况下,它导致了__严重的__性能问题。我将df.any(axis=1)重写为df.agg(["any"], axis=1),在中等大小的数据框上运行几乎需要一分钟的时间。切换回原来的语法后,运行时间恢复正常。我知道这只是个人经验,但也许可以帮助其他人避免困惑。 - lunguini
import time import numpy as np import pandas as pd rng = np.random.default_rng() df = pd.DataFrame(data=rng.integers(0, 2, size=(10_000, 10))) t0 = time.perf_counter() df.any(axis=1).to_frame().transpose() t1 = time.perf_counter() df.agg(['any'], axis=1) t2 = time.perf_counter() print("any.to_frame.transpose", t1 - t0) print("agg", t2 - t1) # any.to_frame.transpose 0.0012745661661028862 # agg 3.5748125459067523 - lunguini
1
在我的笔记本电脑上,any.to_frame.transpose 所需时间为 0.002 秒,agg 所需时间为 3.58 秒。 - lunguini
显示剩余3条评论

5

我不确定早期版本,但截至pandas 0.18.1,可以使用pandas.Series.to_frame方法。

import pandas as pd
df = pd.DataFrame([[1, 2, 3], [2, 3, 3]], columns=['a', 'b', 'c'])
s = df.sum().to_frame(name='sum')

type(s)

>>> pandas.core.frame.DataFrame

name参数是可选的,用于定义列名。


3

0
通过 DF.sum().to_frame() 或直接将聚合结果存储到Dataframe中,不是一个健康的选择。更重要的是,当您想要分别存储聚合值和聚合总和时。使用DF.sum().to_frame将会把值和总和一起存储。
尝试下面的代码以获得更清晰的版本。
a = DF.sum()
sum = list(a)
values = list(a.index)

Series_Dict = {"Agg_Value":values, "Agg_Sum":sum}

Agg_DF = pd.DataFrame(Series_Dict)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接