【问题标题】:Why is DataFrame.loc[[1]] 1,800x slower than df.ix [[1]] and 3,500x than df.loc[1]?为什么 DataFrame.loc[[1]] 比 df.ix [[1]] 慢 1,800 倍,比 df.loc[1] 慢 3,500 倍?
【发布时间】:2015-02-20 04:57:31
【问题描述】:

自己试试吧:

import pandas as pd
s=pd.Series(xrange(5000000))
%timeit s.loc[[0]] # You need pandas 0.15.1 or newer for it to be that slow
1 loops, best of 3: 445 ms per loop

更新:即a legitimate bug in pandas,可能在 2014 年 8 月左右在 0.15.1 中引入。解决方法:等待新版本同时使用旧版本的 pandas;获得尖端的开发人员。来自 github 的版本;在您的pandas 版本中手动进行一行修改;暂时用.ix代替.loc

我有一个包含 480 万行的 DataFrame,使用 .iloc[[ id ]](带有单元素列表)选择单行需要 489 毫秒,几乎是半秒,比 1,800 倍慢相同的 .ix[[ id ]],并且比 .iloc[id]3,500 倍(将 id 作为值传递,而不是作为列表传递)。公平地说,.loc[list] 不管列表的长度如何,所花费的时间都差不多,但我不想在上面花费 489 毫秒,尤其是当 .ix 快一千倍时,并产生相同的结果。我的理解是.ix 应该更慢,不是吗?

我正在使用熊猫 0.15.1。 Indexing and Selecting Data 的优秀教程表明 .ix 在某种程度上比 .loc.iloc 更通用,并且可能更慢。具体来说,它说

但是,当轴基于整数时,仅基于标签的访问和 不支持位置访问。因此,在这种情况下,通常 最好是明确的并使用 .iloc 或 .loc。

这是一个带有基准测试的 iPython 会话:

    print 'The dataframe has %d entries, indexed by integers that are less than %d' % (len(df), max(df.index)+1)
    print 'df.index begins with ', df.index[:20]
    print 'The index is sorted:', df.index.tolist()==sorted(df.index.tolist())

    # First extract one element directly. Expected result, no issues here.
    id=5965356
    print 'Extract one element with id %d' % id
    %timeit df.loc[id]
    %timeit df.ix[id]
    print hash(str(df.loc[id])) == hash(str(df.ix[id])) # check we get the same result

    # Now extract this one element as a list.
    %timeit df.loc[[id]] # SO SLOW. 489 ms vs 270 microseconds for .ix, or 139 microseconds for .loc[id]
    %timeit df.ix[[id]] 
    print hash(str(df.loc[[id]])) == hash(str(df.ix[[id]]))  # this one should be True
    # Let's double-check that in this case .ix is the same as .loc, not .iloc, 
    # as this would explain the difference.
    try:
        print hash(str(df.iloc[[id]])) == hash(str(df.ix[[id]]))
    except:
        print 'Indeed, %d is not even a valid iloc[] value, as there are only %d rows' % (id, len(df))

    # Finally, for the sake of completeness, let's take a look at iloc
    %timeit df.iloc[3456789]    # this is still 100+ times faster than the next version
    %timeit df.iloc[[3456789]]

输出:

The dataframe has 4826616 entries, indexed by integers that are less than 6177817
df.index begins with  Int64Index([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], dtype='int64')
The index is sorted: True
Extract one element with id 5965356
10000 loops, best of 3: 139 µs per loop
10000 loops, best of 3: 141 µs per loop
True
1 loops, best of 3: 489 ms per loop
1000 loops, best of 3: 270 µs per loop
True
Indeed, 5965356 is not even a valid iloc[] value, as there are only 4826616 rows
10000 loops, best of 3: 98.9 µs per loop
100 loops, best of 3: 12 ms per loop

【问题讨论】:

  • 请注意,使用[[id]][id] 是不等价的。 [id] 将返回一个系列,但 [[id]] 将返回一个单行数据帧。
  • @BrenBarn,是的,这解释了.ix 的区别:141 µs 与 270 µs。但是为什么.loc[[id]] 这么慢?

标签: python performance pandas


【解决方案1】:

看起来这个问题在 pandas 0.14 中不存在。我用line_profiler 对其进行了分析,我想我知道发生了什么。由于 pandas 0.15.1,如果给定索引不存在,现在会引发 KeyError。看起来当您使用 .loc[list] 语法时,它正在对整个轴上的索引进行详尽的搜索,即使它已经找到。也就是说,首先,在找到元素的情况下不会提前终止,其次,在这种情况下搜索是蛮力的。

File: .../anaconda/lib/python2.7/site-packages/pandas/core/indexing.py,

  1278                                                       # require at least 1 element in the index
  1279         1          241    241.0      0.1              idx = _ensure_index(key)
  1280         1       391040 391040.0     99.9              if len(idx) and not idx.isin(ax).any():
  1281                                           
  1282                                                           raise KeyError("None of [%s] are in the [%s]" %

【讨论】:

    【解决方案2】:

    Pandas 索引非常慢,我改用 numpy 索引

    df=pd.DataFrame(some_content)
    # takes forever!!
    for iPer in np.arange(-df.shape[0],0,1):
        x = df.iloc[iPer,:].values
        y = df.iloc[-1,:].values
    # fast!        
    vals = np.matrix(df.values)
    for iPer in np.arange(-vals.shape[0],0,1):
        x = vals[iPer,:]
        y = vals[-1,:]
    

    【讨论】:

      猜你喜欢
      • 2012-10-07
      • 1970-01-01
      • 2021-04-12
      • 1970-01-01
      • 2013-08-10
      • 2014-10-04
      • 2018-01-16
      • 2015-04-18
      • 2015-08-03
      相关资源
      最近更新 更多