【问题标题】:Setting values in pandas Series is slow, why?pandas 系列中的设置值很慢,为什么?
【发布时间】:2015-07-27 20:10:32
【问题描述】:

问题

有谁知道为什么直接在熊猫系列上设置项目如此慢?是我做错了什么,还是事情就是这样?

我进行了几次测试,看看最快的方法是在 pandas Series 对象上设置值。以下是结果,按从快到慢的顺序排列:

初始化数组,使用整数索引设置,创建系列

%%timeit
a = np.empty(1000, dtype='float')
for i in range(len(a)):
    a[i] = 1.0
s = pd.Series(data=a)

1000 次循环,最好的 3 次:每个循环 630 µs

创建空列表,使用追加添加项目,创建系列

%%timeit
l = []
for i in range(1000):
    l.append(1.0)
s = pd.Series(data=l)

1000 次循环,3 次中的最佳:每个循环 1.05 毫秒

初始化数组,创建系列,使用 set_value 设置

%%timeit
a = np.empty(1000, dtype='float')
s = pd.Series(data=a)
for i in range(len(a)):
    s.set_value(i, 1.0)

100 次循环,3 次中的最佳:每个循环 18.5 毫秒

初始化数组,创建系列,使用整数索引设置

%%timeit
a = np.empty(1000, dtype='float')
s = pd.Series(data=a)
for i in range(len(a)):
    s[i] = 1.0

10 个循环,3 个循环中的最佳值:每个循环 30.2 毫秒

初始化数组,创建系列,使用iat设置

%%timeit
a = np.empty(1000, dtype='float')
s = pd.Series(data=a)
for i in range(len(a)):
    s.iat[i] = 1.0

10 个循环,3 个循环中的最佳值:每个循环 36.2 毫秒

初始化数组,创建系列,使用 iloc 设置

%%timeit
a = np.empty(1000, dtype='float')
s = pd.Series(data=a)
for i in range(len(a)):
    s.iloc[i] = 1.0

1 次循环,3 次取胜:每个循环 280 毫秒

【问题讨论】:

  • 您的时间也是系列创作的时间。尝试预先创建系列并仅计时设置操作。
  • 试试s.iat[i] = 1.0,我相信这里的索引方法会执行一些检查:pandas.pydata.org/pandas-docs/stable/…iloc 得到 159 毫秒,iat 版本得到 23.3 毫秒
  • @BrenBarn:我尝试只为数组和系列的创建计时,但这只需要 172 微秒
  • @EdChum:编辑了我的答案以包括使用 s.iat[i] 进行设置。它的表现略逊于 s[i]...
  • 是的,我观察到同样的事情,不知道为什么,但它比iloc快得多

标签: python pandas


【解决方案1】:

来自docs

由于使用 [] 进行索引必须处理很多情况(单标签 访问,切片,布尔索引等),它在 为了弄清楚你的要求。

所以我得到以下应该可比较的:

In [13]:

%%timeit
a = np.empty(1000,dtype='float')
s = pd.Series(data=a)
for i in range(len(a)):
    s.iat[i] = 1.0
10 loops, best of 3: 23.3 ms per loop
In [14]:

%%timeit
a = np.empty(1000,dtype='float')
s = pd.Series(data=a)
for i in range(len(a)):
    s.iloc[i] = 1.0
10 loops, best of 3: 159 ms per loop

其他测试:

In [15]:

%%timeit
l = []
for i in range(1000):
    l.append(1.0)
s = pd.Series(data=l)
1000 loops, best of 3: 525 µs per loop
In [16]:

%%timeit
a = np.empty(1000,dtype='float')
s = pd.Series(data=a)
for i in range(len(a)):
    s.set_value(i,1.0)
100 loops, best of 3: 10.1 ms per loop
In [17]:

%%timeit
a = np.empty(1000,dtype='float')
s = pd.Series(data=a)
for i in range(len(a)):
    s[i] = 1.0
100 loops, best of 3: 17.5 ms per loop

【讨论】:

    【解决方案2】:

    我认为这些方法对于将系列初始化为常量值更快:

    基线

    %%timeit
    a = np.empty(1000, dtype='float')
    for i in range(len(a)):
        a[i] = 1.0
    s = pd.Series(data=a)
    
    10000 loops, best of 3: 121 µs per loop
    

    替代品

    %%timeit
    s = pd.Series(np.empty(1000, dtype='float')) * 1.
    
    10000 loops, best of 3: 99.5 µs per loop
    
    %%timeit
    constant = 5.
    s = pd.Series(np.ones(1000)) * constant
    
    10000 loops, best of 3: 85.3 µs per loop
    

    【讨论】:

    • 你当然是对的。在我的问题中,我将每次计算不同值的情况简化为只使用一个常量值(懒得调用随机生成器)。事实上,在我的特殊情况下,它们甚至不是 float 的,而是 object
    【解决方案3】:

    我想出了如何在直接在系列对象上设置值时克服索引开销:

    a = np.empty(1000,dtype='float')
    s = pd.Series(data=a)
    for i in range(len(a)):
        a[i] = 1.0
    

    从 numpy 数组初始化 Series 时,不会复制数据。如果保留对原始数组的引用,则可以在其上设置值!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-04
      • 2018-02-02
      • 2019-10-02
      • 2010-10-30
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多