迭代熊猫系列元素的最佳方式

以下所有内容似乎都适用于迭代熊猫系列的元素。我相信有更多的方法可以做到这一点。有什么区别,哪种方法最好?

import pandas


arr = pandas.Series([1, 1, 1, 2, 2, 2, 3, 3])

# 1
for el in arr:
    print(el)

# 2
for _, el in arr.iteritems():
    print(el)

# 3
for el in arr.array:
    print(el)

# 4
for el in arr.values:
    print(el)

# 5
for i in range(len(arr)):
    print(arr.iloc[i])

回答

TL; 博士

在Pandas 中迭代是一种反模式,通常可以通过向量化、应用、聚合、转换或cythonizing来避免。

但是,如果绝对需要系列迭代,则性能将取决于 dtype 和索引:

指数 如果numpy dtype最快 如果pandas dtype最快 惯用语
不需要 in s.to_numpy() in s.array in s
默认 in enumerate(s.to_numpy()) in enumerate(s.array) in s.items()
风俗 in zip(s.index, s.to_numpy()) in s.items() in s.items()

对于基于 numpy 的系列,请使用 s.to_numpy()

  1. 如果 Series 是python 或numpy dtype ,迭代底层 numpy ndarray 通常是最快的:

    for el in s.to_numpy(): # if dtype is datetime, int, float, str, string
    
    约会时间
    整数 漂浮 浮动 + 南 字符串 细绳
  2. 要访问索引,实际上最快的是enumerate()zip()numpy ndarray:

    for i, el in enumerate(s.to_numpy()): # if default range index
    
    for i, el in zip(s.index, s.to_numpy()): # if custom index
    

    两者都比惯用的s.items()/快s.iteritems()

    日期时间 + 索引
  3. 微优化,切换到s.tolist()更短int/ float/str系列:

    for el in s.to_numpy(): # if >100K elements
    
    for el in s.tolist(): # to micro-optimize if <100K elements
    

    警告:不要使用,list(s)因为它不使用编译代码,这会使它变慢。


对于基于熊猫的系列,请使用s.arrays.items()

Pandas 扩展 dtypes包含额外的(元)数据,例如:

大熊猫数据类型 内容
Categorical 2个阵列
DatetimeTZ 数组 + 时区元数据
Interval 2个阵列
Period 数组 + 频率元数据
... ...

将这些扩展数组转换为 numpy “可能很昂贵”,因为它可能涉及复制/强制数据,因此:

  1. 如果 Series 是Pandas 扩展 dtype,则迭代底层 Pandas 数组通常是最快的:

    for el in s.array: # if dtype is pandas-only extension
    

    例如,有 ~100 个唯一Categorical值:

    分类的
    日期时间TZ 时期 间隔
  2. 要访问索引,s.items() pandas dtypes的惯用语非常快:

    for i, el in s.items(): # if need index for pandas-only dtype
    
    日期时间TZ + 索引 间隔 + 索引 期间+索引
  3. 要进行微优化,请切换到enumerate()默认索引Categorical数组的稍微快一点:

    for i, el in enumerate(s.array): # to micro-optimize Categorical dtype if need default range index
    
    分类+索引

注意事项

  1. 避免使用s.values

    • 使用s.to_numpy()得到根本numpy的ndarray
    • s.array获得的潜在大熊猫阵列
  2. 避免修改迭代的 Series

    永远不应该修改你正在迭代的东西。这不能保证在所有情况下都有效。根据数据类型,迭代器返回一个副本而不是一个视图,写入它没有任何效果!

  3. 尽可能避免手动迭代

    1. 向量化、(布尔)索引等。

    2. 应用函数,例如:

      • s.apply(some_function)
      • s.agg(['min', 'max', 'mean'])
      • s.transform([np.sqrt, np.exp])

      注意:这些是不是尽管常见的误解vectorizations。

    3. 卸载到 cython/numba


规格:的ThinkPad X1极端创3(核心i7-10850H 2.70GHz,32GB DDR4 2933MHz)

版本:python==3.9.2pandas==1.3.1numpy==1.20.2

测试数据:系列生成代码段中的代码

'''
Note: This is python code in a js snippet, so "run code snippet" will not work.
The snippet is just to avoid cluttering the main post with supplemental code.
'''

import pandas as pd
import numpy as np

int_series = pd.Series(np.random.randint(1000000000, size=n))
float_series = pd.Series(np.random.randn(size=n))
floatnan_series = pd.Series(np.random.choice([np.nan, np.inf]*n + np.random.randn(n).tolist(), size=n))
str_series = pd.Series(np.random.randint(10000000000000000, size=n)).astype(str)
string_series = pd.Series(np.random.randint(10000000000000000, size=n)).astype('string')
datetime_series = pd.Series(np.random.choice(pd.date_range('2000-01-01', '2021-01-01'), size=n))
datetimetz_series = pd.Series(np.random.choice(pd.date_range('2000-01-01', '2021-01-01', tz='CET'), size=n))
categorical_series = pd.Series(np.random.randint(100, size=n)).astype('category')
interval_series = pd.Series(pd.arrays.IntervalArray.from_arrays(-np.random.random(size=n), np.random.random(size=n)))
period_series = pd.Series(pd.period_range(end='2021-01-01', periods=n, freq='s'))


以上是迭代熊猫系列元素的最佳方式的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>