【问题标题】:Adding many series efficiently?有效地添加许多系列?
【发布时间】:2019-03-16 16:08:56
【问题描述】:

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

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

这比我预期的要花更多的时间。有什么办法可以显着加快速度?

【问题讨论】:

  • .fillna(0)fill_value=0 之后不是多余的吗?
  • 我不知道这是否对您的特定情况有帮助,但通常添加Series、附加到DataFrames 等非常慢。你能合并原始数据,然后在最后构造一个Series 对象吗?
  • @ALollz:是的,在这种情况下,我也用它来添加框架。
  • @Batman:谢谢,我怀疑,只是想知道我是否遗漏了一些明显的东西。我会尽量按照你建议的方式处理它

标签: python pandas performance series


【解决方案1】:

使用concat

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

【讨论】:

  • 感谢您的回答。稍微快一点,但只有大约 10%。似乎它本质上是缓慢的过程
【解决方案2】:

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

以下解决方案假设每个系列都按索引对齐,即每个系列的 kth 项按位置在每个 k 的系列中是可比较的em>。

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

【讨论】:

  • 谢谢,但他们考虑不同的时间间隔。甚至可能没有相同的大小。
  • @blue_note,请参阅更新,您也可以使用 NumPy 填充您的数组以使其大小相同。我看到特定参数的改进约为 3 倍。
  • @blue_note 如果您依赖 pandas 的索引对齐行为,那么您实际上是在对每个添加进行连接。这比仅仅跨向量相加要昂贵得多。
  • @shadowtalker,是的,我依赖索引对齐。目前尚不清楚这是否是 OP 用例的症结所在。
【解决方案3】:

您可以使用pd.concat,但可以使用axis=0,然后在level=0 上使用groupby,例如:

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

all_my_items 包含 1000 个不同长度(例如 2000 到 2500 之间)和不同时间间隔的 pd.Series,例如:

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

所以结果是一样的,运算速度更快

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    相关资源
    最近更新 更多