有效添加多个系列?

时间:2018-10-11 14:15:59

标签: python pandas performance series

我有数千个pd.Series项目,我只想添加它们。他们考虑不同的时间间隔,我需要用零填充缺失的值。我尝试过

add_series = lambda a, b: a.add(b, fill_value=0).fillna(0)
result = reduce(add_series, all_my_items)

这比我预期的要花费更多的时间。有什么方法可以大大加快速度吗?

3 个答案:

答案 0 :(得分:2)

使用concat

pd.concat(all_my_items,axis=1).fillna(0).sum(axis=1)

答案 1 :(得分:0)

您可以通过np.padnp.vstack下拉至NumPy。为了提高性能,在操作Pandas / NumPy对象时,应避免使用常规的Python方法。

以下解决方案假定每个系列均按索引对齐,即,每个系列的 k th 项目按位置在每个 k的系列中具有可比性

np.random.seed(0)
m, n = 10**2, 10**4
S = [pd.Series(np.random.random(np.random.randint(0, m))) for _ in range(n)]

def combiner(arrs):
    n = max(map(len, arrs))
    L = [np.pad(i.values, (0, n-len(i)), 'constant') for i in arrs]
    return np.vstack(L).sum(0)

res1 = pd.concat(L, axis=1).fillna(0).sum(axis=1)
res2 = pd.Series(combiner(S))
assert (res1 == res2).all()

%timeit pd.concat(L, axis=1).fillna(0).sum(axis=1)  # 2.63 s per loop
%timeit pd.Series(combiner(S))                      # 863 ms per loop

答案 2 :(得分:0)

您可以使用pd.concat,但可以同时使用axis=0groupby上的level=0,例如:

pd.concat(all_my_items,axis=0).groupby(level=0).sum()

其中all_my_items包含1000个pd.Series,它们的长度不同(例如2000年至2500年之间),并且具有不同的时间间隔,例如:

import numpy as np

np.random.seed(0)
n = 1000 #number of series
#lengths of the series
len_ser = np.random.randint(2000, 2500, n)
# to pick a random start date 
list_date = pd.date_range(start = pd.to_datetime('1980-01-01'), periods=15000).tolist()
# generate the list of pd.Series
all_my_items = [pd.Series(range(len_ser[i]), 
                          index=pd.date_range(start=list_date[np.random.randint(0,15000,1)[0]], 
                                              periods=len_ser[i])) 
               for i in range(n)]

# Wen's solution
%timeit pd.concat(all_my_items,axis=1).fillna(0).sum(axis=1) #1.47 s ± 138 ms per loop
#this solution
%timeit pd.concat(all_my_items,axis=0).groupby(level=0).sum() #270 ms ± 11.3 ms

#verify same result
print (pd.concat(all_my_items,axis=1).fillna(0).sum(axis=1) == 
       pd.concat(all_my_items,axis=0).groupby(level=0).sum()).all()) #True

所以结果是一样的,而且操作更快