Добавление многих серий эффективно? - PullRequest
0 голосов
/ 11 октября 2018

У меня есть тысячи pd.Series предметов, и я просто хочу их добавить.Они учитывают разные временные интервалы, и мне нужно дополнить пропущенные значения нулями.Я попытался

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

, что занимает больше времени, чем я ожидал.Есть ли способ значительно ускорить это?

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

Вы можете перейти к NumPy через np.pad и np.vstack.Для повышения производительности, если возможно, следует избегать обычных методов Python при манипулировании объектами Pandas / NumPy.

В приведенном ниже решении предполагается, что каждая серия выравнивается по индексу, то есть 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
0 голосов
/ 11 октября 2018

Вы можете использовать pd.concat, но с axis=0, а затем groupby на 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

Таким образом, результат тот же, и операция быстрее

0 голосов
/ 11 октября 2018

Использование concat

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