获取熊猫系列

时间:2017-11-11 15:05:08

标签: python pandas

假设

s = pd.Series(range(50))

0      0
1      1
2      2
3      3
...
48     48
49     49

如何获得由每n行总和组成的新系列?

当n = 5时,预期结果如下;

0      10
1      35
2      60
3      85
...
8      210
9      235

如果使用loc或iloc并通过python循环,当然可以完成,但我相信它可以简单地用Pandas方式完成。

此外,这是一个非常简单的例子,我不期待序列的解释:)。 I尝试的实际数据系列将时间索引和每秒发生的事件数作为值。

2 个答案:

答案 0 :(得分:11)

Series.groupby + DataFrameGroupBy.sum

N = 5
s.groupby(s.index // N).sum()

0     10
1     35
2     60
3     85
4    110
5    135
6    160
7    185
8    210
9    235
dtype: int64

将索引分为5组并相应地分组。

numpy.reshape + ndarray.sum

如果大小是N(或5)的倍数,您可以重塑并添加:

s.values.reshape(-1, N).sum(1)
# array([ 10,  35,  60,  85, 110, 135, 160, 185, 210, 235])

numpy.add.at

b = np.zeros(len(s) // N)
np.add.at(b, s.index // N, s.values)
b
# array([ 10.,  35.,  60.,  85., 110., 135., 160., 185., 210., 235.])

答案 1 :(得分:1)

在下面的示例中,我能想到的最有效的解决方案是 f1()。它比在另一个答案中使用 groupby 快几个数量级。 请注意,当数组的长度不是精确倍数时, f1() 不起作用,例如如果你想每 2 项求和一个 3 项数组。 对于这些情况,您可以使用 f1v2():

f1v2( [0,1,2,3,4] ,2 ) = [1,5,4]

我的代码如下。我已使用 timeit 进行比较:

import timeit
import numpy as np
import pandas as pd


def f1(a,x):
    if isinstance(a, pd.Series):
        a = a.to_numpy()
    return a.reshape((int(a.shape[0]/x), int(x) )).sum(1)

def f2(myarray, x):
  return [sum(myarray[n: n+x]) for n in range(0, len(myarray), x)]

def f3(myarray, x):
    s = pd.Series(myarray)
    out = s.groupby(s.index // 2).sum()
    return out

def f1v2(a,x):
    if isinstance(a, pd.Series):
        a = a.to_numpy()
        
    mod = a.shape[0] % x
    if  mod != 0:
        excl = a[-mod:]
        keep = a[: len(a) - mod]
        out = keep.reshape((int(keep.shape[0]/x), int(x) )).sum(1)
        out = np.hstack( (excl.sum() , out) ) 
    else:       
        out = a.reshape((int(a.shape[0]/x), int(x) )).sum(1)
    
    return out
    

a = np.arange(0,1e6)

out1 = f1(a,2)
out2 = f2(a,2)
out3 = f2(a,2)

t1 = timeit.Timer( "f1(a,2)" , globals = globals() ).repeat(repeat = 5, number = 2)
t1v2 = timeit.Timer( "f1v2(a,2)" , globals = globals() ).repeat(repeat = 5, number = 2)
t2 = timeit.Timer( "f2(a,2)" , globals = globals() ).repeat(repeat = 5, number = 2)
t3 = timeit.Timer( "f3(a,2)" , globals = globals() ).repeat(repeat = 5, number = 2)

resdf = pd.DataFrame(index = ['min time'])
resdf['f1'] = [min(t1)]
resdf['f1v2'] = [min(t1v2)]
resdf['f2'] = [min(t2)]
resdf['f3'] = [min(t3)]
#the docs explain why it makes more sense to take the min than the avg
resdf = resdf.transpose()
resdf['% difference vs fastes'] = (resdf /resdf.min() - 1) * 100

b = np.array( [0,1,2,4,5,6,7] )

out1v2 = f1v2(b,2)