Pandas使用pandas.Series处理单行或单列数据,这比在DataFrame结构中处理更快。
当您需要时,Pandas使用pandas.Series来处理:
%%timeit -n 10
df['b']
2.31 µs ± 1.59 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
然而,如果我将其放在列表中,就可以调用相同列的DataFrame。那么你会得到:
%%timeit -n 10
df[['b']]
90.7 ms ± 1.73 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
你可以从上面看到,Series的表现优于DataFrame。
以下是Pandas如何使用列“b”。
type(df['b'])
pandas.core.series.Series
type(df[['b']])
pandas.core.frame.DataFrame
编辑:
由于OP想深入了解为什么pd.series与pd.dataframe相比速度更快,我将进一步扩展我的答案。同时,这也是一个很好的问题,可以拓展我们对底层技术如何工作的理解。请那些有更多专业知识的人参与讨论。
首先,让我们从numpy开始,因为它是pandas的一个构建块。根据《Python数据分析》和pandas作者Wes McKinney的说法,numpy在性能上比python有所提升:
This is based partly on performance differences having to do with the
cache hierarchy of the CPU; operations accessing contiguous blocks of memory (e.g.,
summing the rows of a C order array) will generally be the fastest because the mem‐
ory subsystem will buffer the appropriate blocks of memory into the ultrafast L1 or
L2 CPU cache.
我们来看一下这个例子的速度差异。让我们从数据框的列“b”中创建一个numpy数组。
a = np.array(df['b'])
现在进行性能测试:
%%timeit -n 10
a
结果如下:
32.5 ns ± 28.2 ns per loop (mean ± std. dev. of 7 runs, 10 loops each)
相对于 pd.series 的执行时间2.31微秒,这是一次严重的性能提升。
性能提升的另一个主要原因在于,NumPy 的索引直接进入 NumPy C 扩展,但是当您索引到 Series 时,会发生大量的 Python 操作,这会导致速度较慢。(阅读本文)
现在让我们来看看为什么:
df.iloc[:,1:3]
大幅超过预期:
df.iloc[:,[1,2]]
有趣的是,在这种情况下,.loc 与 .iloc 的性能影响相同。
我们第一个发现事情不对劲的线索在下面的代码中:
df.iloc[:,1:3] is df.iloc[:,[1,2]]
False
这两个表达式得到相同的结果,但是它们是不同的对象。我进行了深入研究,试图找出它们之间的区别。但是我在互联网上和我的书库中都没有找到相关参考资料。
通过查看源代码,我们可以开始看到一些差异。我指的是 indexing.py。
在 _iLocIndexer 类中,我们可以发现 pandas 为 iloc 切片中的列表做了一些额外的工作。
当检查输入时,我们立即遇到这两个差异:
if isinstance(key, slice):
return
对比。
elif is_list_like_indexer(key):
# check that the key does not exceed the maximum size of the index
arr = np.array(key)
l = len(self.obj._get_axis(axis))
if len(arr) and (arr.max() >= l or arr.min() < -l):
raise IndexError("positional indexers are out-of-bounds")
单单这个原因就足够导致性能降低吗?我不确定。
虽然 .loc 稍有不同,但它也会在使用值列表时降低性能。查看 index.py 文件,找到 class _LocIndexer(_LocationIndexer) 中的 def _getitem_axis(self, key, axis=None): --> 部分:
处理列表输入的 is_list_like_indexer(key) 代码部分相当冗长,包含了很多开销。其中包含一条注释:
# convert various list-like indexers
# to a list of keys
# we will use the *values* of the object
# and NOT the index if its a PandasObject
处理值列表或整数时,相比于直接切片会增加足够的开销,这可能会导致处理延迟。
其余代码超出了我的薪资等级。如果有人能够查看并进行评价,那将不胜感激。
df.iloc[:, 1:2]
中的一列。 - Mohit Motwaniloc
和iloc
切片行和列有关。这就是为什么如果您在使用[]
运算符切片列之前使用[]
运算符切片行,您会得到类似于loc
和iloc
的结果:df[:]['b']
。我还想象时间差异与返回Series或DataFrame有关。 - It_is_Chris