更多Pythonic / Pandaic循环大熊猫系列

时间:2017-01-05 12:44:17

标签: python loops pandas numpy

这很可能是非常基本的东西,但我无法弄清楚。 假设我有一个这样的系列:

s1 = pd.Series([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])

如何在不必恢复使用for-loop的情况下对本系列的子系列进行操作?

例如,假设我想将其转换为包含四个元素的新系列。这个新系列的第一个元素是原始系列(1,1,1)中前三个元素的总和,第二个元素是后三个元素(2,2,2)的总和等:

s2 = pd.Series([3, 6, 9, 12])

我该怎么做?

4 个答案:

答案 0 :(得分:7)

您还可以使用np.add.reduceat指定要在每个第3个元素处减少的切片并计算其运行总和:

>>> pd.Series(np.add.reduceat(s1.values, np.arange(0, s1.shape[0], 3)))
0     3
1     6
2     9
3    12
dtype: int64

时间限制:

arr = np.repeat(np.arange(10**5), 3)
s = pd.Series(arr)
s.shape
(300000,)

# @IanS soln
%timeit s.rolling(3).sum()[2::3]        
100 loops, best of 3: 15.6 ms per loop

# @Divakar soln
%timeit pd.Series(np.bincount(np.arange(s.size)//3, s))  
100 loops, best of 3: 5.44 ms per loop

# @Nikolas Rieble soln
%timeit pd.Series(np.sum(np.array(s).reshape(len(s)/3,3), axis = 1))  
100 loops, best of 3: 2.17 ms per loop

# @Nikolas Rieble modified soln
%timeit pd.Series(np.sum(np.array(s).reshape(-1, 3), axis=1))  
100 loops, best of 3: 2.15 ms per loop

# @Divakar modified soln
%timeit pd.Series(s.values.reshape(-1,3).sum(1))
1000 loops, best of 3: 1.62 ms per loop

# Proposed solution in post
%timeit pd.Series(np.add.reduceat(s.values, np.arange(0, s.shape[0], 3)))
1000 loops, best of 3: 1.45 ms per loop

答案 1 :(得分:6)

这是使用np.bincount处理通用数量元素的NumPy方法 -

pd.Series(np.bincount(np.arange(s1.size)//3, s1))

示例运行 -

In [42]: s1 = pd.Series([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 9, 5])

In [43]: pd.Series(np.bincount(np.arange(s1.size)//3, s1))
Out[43]: 
0     3.0
1     6.0
2     9.0
3    12.0
4    14.0
dtype: float64

如果我们真的渴望表现以及系列的长度可以被窗口长度整除的情况,我们可以使用s1.values,然后reshape查看系列视图,最后使用np.einsum总结,如此 -

pd.Series(np.einsum('ij->i',s.values.reshape(-1,3)))

@Nickil Maveli's post -

中使用的基准数据集相同的计时
In [140]: s = pd.Series(np.repeat(np.arange(10**5), 3))

# @Nickil Maveli's soln
In [141]: %timeit pd.Series(np.add.reduceat(s.values, np.arange(0, s.shape[0], 3)))
100 loops, best of 3: 2.07 ms per loop

# Using views+sum
In [142]: %timeit pd.Series(s.values.reshape(-1,3).sum(1))
100 loops, best of 3: 2.03 ms per loop

# Using views+einsum
In [143]: %timeit pd.Series(np.einsum('ij->i',s.values.reshape(-1,3)))
1000 loops, best of 3: 1.04 ms per loop

答案 2 :(得分:4)

您可以使用numpy对系列s1进行整形,然后对诸如以下的行进行求和:

np.sum(np.array(s1).reshape(len(s1)/3,3), axis = 1)

导致

array([ 3,  6,  9, 12], dtype=int64)

编辑:正如他在评论中提到的MSeifert,你也可以让numpy计算长度,例如:

np.sum(np.array(s1).reshape(-1, 3), axis=1)

答案 3 :(得分:3)

这计算滚动总和:

s1.rolling(3).sum()

您只需选择每个第三个元素:

s1.rolling(3).sum()[2::3]

输出:

2      3.0
5      6.0
8      9.0
11    12.0