如何在Pandas中的DataFrame中遍历行

我有一个熊猫数据框,df

   c1   c20  10  1001  11  1102  12  120

如何迭代此数据框的行?对于每一行,我希望能够通过列的名称访问其元素(单元格中的值)。例如:

for row in df.rows:print(row['c1'], row['c2'])

我发现了一个类似的问题,建议使用其中任何一个:

for date, row in df.T.iteritems():
for row in df.iterrows():

但我不明白row对象是什么以及如何使用它。

5985652 次浏览

您应该使用#0。虽然逐行迭代不是特别有效,因为必须创建Series对象。

#0是一个生成索引和行的生成器(作为一个系列):

import pandas as pd
df = pd.DataFrame({'c1': [10, 11, 12], 'c2': [100, 110, 120]})df = df.reset_index()  # make sure indexes pair with number of rows
for index, row in df.iterrows():print(row['c1'], row['c2'])
10 10011 11012 120

您还可以使用df.apply()遍历行并访问函数的多列。

docs:DataFrame.apply()

def valuation_formula(x, y):return x * y * 0.5
df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)

虽然iterrows()是一个很好的选择,但有时itertuples()可以更快:

df = pd.DataFrame({'a': randn(1000), 'b': randn(1000),'N': randint(100, 1000, (1000)), 'x': 'x'})
%timeit [row.a * 2 for idx, row in df.iterrows()]# => 10 loops, best of 3: 50.3 ms per loop
%timeit [row[1] * 2 for row in df.itertuples()]# => 1000 loops, best of 3: 541 µs per loop

您可以使用#0函数如下:

for i in range(0, len(df)):print(df.iloc[i]['c1'], df.iloc[i]['c2'])

首先考虑您是否真的需要在DataFrame中的行上迭代。有关替代方案,请参阅这个答案

如果您仍然需要遍历行,您可以使用下面的方法。注意一些在任何其他答案中都没有提到的重要警告

itertuples()应该比iterrows()

但请注意,根据文档(目前熊猫0.24.2):

  • 迭代:dtype可能不匹配行到行

因为iterrow为每一行返回一个Series,所以它并不保存跨行dtype(dtype在DataFrames的跨列保留)。为了在迭代行时保留dtype,最好使用迭代元组(),它返回值的命名元组,并且通常比iterrow()快得多

  • 迭代:不修改行

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

使用DataFrame.apply()代替:

    new_df = df.apply(lambda x: x * 2, axis = 1)
  • 迭代:

如果列名是无效的Python标识符、重复的或以下划线开头,则列名将重命名为位置名称。对于大量列(>255),将返回常规元组。

查看熊猫文档迭代开发了解更多详情。

要循环dataframe中的所有行,您可以使用:

for x in range(len(date_example.index)):print date_example['Date'].iloc[x]
 for ind in df.index:print df['c1'][ind], df['c2'][ind]

您可以编写自己的迭代器来实现namedtuple

from collections import namedtuple
def myiter(d, cols=None):if cols is None:v = d.values.tolist()cols = d.columns.values.tolist()else:j = [d.columns.get_loc(c) for c in cols]v = d.values[:, j].tolist()
n = namedtuple('MyTuple', cols)
for line in iter(v):yield n(*line)

这与pd.DataFrame.itertuples直接相当。我的目标是以更高的效率执行相同的任务。


对于给定的带有我的函数的数据帧:

list(myiter(df))
[MyTuple(c1=10, c2=100), MyTuple(c1=11, c2=110), MyTuple(c1=12, c2=120)]

或者pd.DataFrame.itertuples

list(df.itertuples(index=False))
[Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]

一个全面的测试
我们测试使所有列可用并子集列。

def iterfullA(d):return list(myiter(d))
def iterfullB(d):return list(d.itertuples(index=False))
def itersubA(d):return list(myiter(d, ['col3', 'col4', 'col5', 'col6', 'col7']))
def itersubB(d):return list(d[['col3', 'col4', 'col5', 'col6', 'col7']].itertuples(index=False))
res = pd.DataFrame(index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],columns='iterfullA iterfullB itersubA itersubB'.split(),dtype=float)
for i in res.index:d = pd.DataFrame(np.random.randint(10, size=(i, 10))).add_prefix('col')for j in res.columns:stmt = '{}(d)'.format(j)setp = 'from __main__ import d, {}'.format(j)res.at[i, j] = timeit(stmt, setp, number=100)
res.groupby(res.columns.str[4:-1], axis=1).plot(loglog=True);

在此处输入图片描述

在此处输入图片描述

您还可以执行NumPy索引以获得更高的速度。它不是真正的迭代,但在某些应用程序中比迭代效果好得多。

subset = row['c1'][0:5]all = row['c1'][:]

你可能还想将其转换为数组。这些索引/选择应该像NumPy数组一样工作,但我遇到了问题并需要转换

np.asarray(all)imgs[:] = cv2.resize(imgs[:], (224,224) ) # Resize every image in an hdf5 file

我一直在寻找如何在行上迭代并在这里结束:

for i, row in df.iterrows():for j, column in row.iteritems():print(column)

要循环每行方便dataframe使用值中的所有行,可以将namedtuples转换为ndarrays。例如:

df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])

遍历行:

for row in df.itertuples(index=False, name='Pandas'):print np.asarray(row)

结果:

[ 1.   0.1][ 2.   0.2]

请注意,如果index=True索引被添加为元组的第一个元素,这对于某些应用可能是不期望的。

有时一个有用的模式是:

# Borrowing @KutalmisB df exampledf = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])# The to_dict call results in a list of dicts# where each row_dict is a dictionary with k:v pairs of columns:value for that rowfor row_dict in df.to_dict(orient='records'):print(row_dict)

其结果是:

{'col1':1.0, 'col2':0.1}{'col1':2.0, 'col2':0.2}

有很多方法可以迭代Pandas数据框中的行。一种非常简单和直观的方法是:

df = pd.DataFrame({'A':[1, 2, 3], 'B':[4, 5, 6], 'C':[7, 8, 9]})print(df)for i in range(df.shape[0]):# For printing the second columnprint(df.iloc[i, 1])
# For printing more than one columnsprint(df.iloc[i, [0, 2]])

对于查看和修改值,我会使用iterrows()。在for循环中并通过使用元组解包(参见示例:i, row),我使用row仅查看值,并在想要修改值时使用iloc方法。正如前面的答案所述,在这里你不应该修改你正在迭代的东西。

for i, row in df.iterrows():df_column_A = df.loc[i, 'A']if df_column_A == 'Old_Value':df_column_A = 'New_value'

这里循环中的row是该行的副本,而不是它的视图。因此,您不应该编写类似row['A'] = 'New_Value'的内容,它不会修改DataFrame。但是,您可以使用iloc并指定DataFrame来完成这项工作。

此示例使用iloc隔离数据帧中的每个数字。

import pandas as pd
a = [1, 2, 3, 4]b = [5, 6, 7, 8]
mjr = pd.DataFrame({'a':a, 'b':b})
size = mjr.shape
for i in range(size[0]):for j in range(size[1]):print(mjr.iloc[i, j])

如何在Pandas中的DataFrame中遍历行

答案:不要*

Pandas中的迭代是一种反模式,只有当你用尽所有其他选项时才应该这样做。你不应该使用任何名称中带有“iter”的函数超过几千行,否则你将不得不习惯等待的很多

您想打印DataFrame吗?使用#0

你想计算一些东西吗?在这种情况下,按此顺序搜索方法(列表从这里修改):

  1. 向量化
  2. Cython例程
  3. 列表理解(vanillafor循环)
  4. #0:i)可以在Cython中执行的缩减,ii)Python空间中的迭代
  5. #0#1
  6. DataFrame.iterrows()

iterrowsitertuples(都在这个问题的答案中获得了很多投票)应该在非常罕见的情况下使用,例如生成行对象/命名组进行顺序处理,这实际上是这些函数唯一有用的东西。

向当局上诉

迭代中的留档页面有一个巨大的红色警告框,上面写着:

遍历熊猫对象通常很慢。在许多情况下,不需要手动遍历行[…]。

*它实际上比“don't”复杂一点。df.iterrows()是这个问题的正确答案,但是“向量化你的操作”是更好的答案。我承认有些情况下无法避免迭代(例如,某些操作的结果取决于为前一行计算的值)。然而,需要熟悉库才能知道何时。如果你不确定是否需要迭代解决方案,你可能不需要。PS:要了解更多关于我编写这个答案的基本原理,跳到最底部。


比循环更快:向量化Cython

熊猫(通过NumPy或Cythonized函数)对许多基本操作和计算进行了“矢量化”。这包括算术、比较、(大多数)约简、重塑(如枢转)、连接和分组操作。查看基本功能上的留档,为您的问题找到合适的矢量化方法。

如果不存在,请随意使用自定义cython扩展编写自己的。


下一个最好的事情:列表理解*

如果1)没有可用的矢量化解决方案,2)性能很重要,但不足以完成代码的细胞化麻烦,3)你正在尝试对代码执行元素转换,列表推导应该是你的下一个选择。有一个大量的证据表明列表推导对于许多常见的Pandas任务来说足够快(甚至有时更快)。

公式很简单,

# Iterating over one column - `f` is some function that processes your dataresult = [f(x) for x in df['col']]# Iterating over two columns, use `zip`result = [f(x, y) for x, y in zip(df['col1'], df['col2'])]# Iterating over multiple columns - same data typeresult = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].to_numpy()]# Iterating over multiple columns - differing data typeresult = [f(row[0], ..., row[n]) for row in zip(df['col1'], ..., df['coln'])]

如果您可以将业务逻辑封装到函数中,则可以使用调用它的列表推导。您可以通过原始Python代码的简单性和速度使任意复杂的事情工作。

警告

列表推导假设您的数据易于使用-这意味着您的数据类型是一致的并且您没有NaN,但这并不能总是得到保证。

  1. 第一个更明显,但是在处理NaN时,如果存在内置的Pandas方法(因为它们具有更好的角落案例处理逻辑),则更喜欢它们,或者确保您的业务逻辑包含适当的NaN处理逻辑。
  2. 在处理混合数据类型时,您应该迭代zip(df['A'], df['B'], ...)而不是df[['A', 'B']].to_numpy(),因为后者隐式地将数据上转换为最常见的类型。例如,如果A是数字,B是字符串,to_numpy()将整个数组转换为字符串,这可能不是您想要的。幸运的是,zip将您的列组合在一起是最直接的解决方法。

*您的里程可能会因上述注意事项部分中列出的原因而有所不同。


一个明显的例子

让我们通过添加两个熊猫列A + B的简单示例来演示差异。这是一个向量化操作,因此很容易对比上面讨论的方法的性能。

基准代码,供大家参考.底部的一行测量了一个用numpandas编写的函数,这是一种Pandas风格,与NumPy大量混合以挤出最大性能。除非你知道自己在做什么,否则应该避免编写numpandas代码。尽可能坚持API(即,更喜欢vec而不是vec_numpy)。

然而,我应该提到,事情并不总是这么简单。有时,“什么是最好的操作方法”的答案是“这取决于你的数据”。我的建议是,在确定一种方法之前,先根据你的数据测试不同的方法。


个人观点*

对iter系列的各种替代方案进行的大多数分析都是通过性能的角度进行的。然而,在大多数情况下,您通常会处理一个合理大小的数据集(不超过几千或100K行),性能将仅次于解决方案的简单性/易读性。

这是我在选择解决问题的方法时的个人偏好。

对于新手:

向量化(如果可能);#0;列表理解;#1/#2;#3; Cython

对于更有经验的人:

向量化(如果可能);#0;列表理解;Cython;#1/#2;#3

对于任何可以向量化的问题,向量化都是最惯用的方法。始终寻求向量化!如有疑问,请查阅文档,或查看Stack Overflow以获取有关您特定任务的现有问题。

在我的很多帖子中,我确实倾向于继续谈论apply有多糟糕,但我承认初学者更容易理解它在做什么。此外,在我的这篇文章中解释了apply的很多用例。

Cython在列表中排名较低,因为正确完成需要更多的时间和精力。你通常不需要用熊猫编写需要这种性能水平的代码,即使是列表理解也无法满足。

*与任何个人意见一样,请用盐堆!


进一步阅读

*Pandas字符串方法是“向量化”的,因为它们在系列上指定,但对每个元素进行操作。底层机制仍然是迭代的,因为字符串操作本质上很难向量化。


我为什么要写这个答案

我注意到新用户的一个共同趋势是问“我如何迭代我的df来做X?”形式的问题。显示调用iterrows()的代码,同时在for循环内做某事。这是为什么。一个没有被引入矢量化概念的库新用户可能会设想解决他们问题的代码是迭代他们的数据来做某事。不知道如何迭代DataFrame,他们做的第一件事就是谷歌它,最后在这里,在这个问题上。然后他们看到被接受的答案告诉他们如何去做,他们闭上眼睛运行这段代码,而不会首先质疑迭代是否是正确的事情。

这个答案的目的是帮助新用户理解迭代并不一定能解决所有问题,还有更好、更快、更惯用的解决方案,值得花时间探索它们。我不想发起迭代与向量化的战争,但我希望新用户在使用这个库开发问题的解决方案时能被告知。

有一种方法可以迭代抛出行,同时返回DataFrame,而不是Series。我没有看到有人提到你可以将索引作为列表传递给要作为DataFrame返回的行:

for i in range(len(df)):row = df.iloc[[i]]

注意双括号的用法。这将返回一个单行的DataFrame。

有些库(例如我使用的Java互操作库)要求一次以行方式传递值,例如,如果流式传输数据。为了复制流式传输的性质,我逐个“流式传输”我的数据帧值,我写了下面的内容,它不时派上用场。

class DataFrameReader:def __init__(self, df):self._df = dfself._row = Noneself._columns = df.columns.tolist()self.reset()self.row_index = 0
def __getattr__(self, key):return self.__getitem__(key)
def read(self) -> bool:self._row = next(self._iterator, None)self.row_index += 1return self._row is not None
def columns(self):return self._columns
def reset(self) -> None:self._iterator = self._df.itertuples()
def get_index(self):return self._row[0]
def index(self):return self._row[0]
def to_dict(self, columns: List[str] = None):return self.row(columns=columns)
def tolist(self, cols) -> List[object]:return [self.__getitem__(c) for c in cols]
def row(self, columns: List[str] = None) -> Dict[str, object]:cols = set(self._columns if columns is None else columns)return {c : self.__getitem__(c) for c in self._columns if c in cols}
def __getitem__(self, key) -> object:# the df index of the row is at index 0try:if type(key) is list:ix = [self._columns.index(key) + 1 for k in key]else:ix = self._columns.index(key) + 1return self._row[ix]except BaseException as e:return None
def __next__(self) -> 'DataFrameReader':if self.read():return selfelse:raise StopIteration
def __iter__(self) -> 'DataFrameReader':return self

它可以用来:

for row in DataFrameReader(df):print(row.my_column_name)print(row.to_dict())print(row['my_column_name'])print(row.tolist())

并保留正在迭代的行的值/名称映射。显然,比上面指示的使用应用程序和Cython慢得多,但在某些情况下是必要的。

如何高效迭代

如果你真的必须迭代Pandas数据框,你可能会想要避免使用迭代()。有不同的方法,通常的iterrows()远不是最好的。迭代()可以快100倍。

简而言之:

  • 作为一般规则,请使用df.itertuples(name=None)。特别是当您有固定数量的列且少于255列时。见(3)
  • 否则,使用df.itertuples(),除非您的列具有特殊字符,例如空格或 '-'. 见(2)
  • 通过使用最后一个示例,即使您的数据框有奇怪的列,也可以使用itertuples()见(4)
  • 如果您不能使用以前的解决方案,则仅使用iterrows()见(1)

在Pandas数据框中迭代行的不同方法:

生成一个包含一百万行和4列的随机数据帧:

    df = pd.DataFrame(np.random.randint(0, 100, size=(1000000, 4)), columns=list('ABCD'))print(df)

1)通常的iterrows()很方便,但很慢:

start_time = time.clock()result = 0for _, row in df.iterrows():result += max(row['B'], row['C'])
total_elapsed_time = round(time.clock() - start_time, 2)print("1. Iterrows done in {} seconds, result = {}".format(total_elapsed_time, result))

2)默认的itertuples()已经快得多,但它不适用于My Col-Name is very Strange等列名(如果您的列重复或列名不能简单地转换为Python变量名,则应避免此方法)。

start_time = time.clock()result = 0for row in df.itertuples(index=False):result += max(row.B, row.C)
total_elapsed_time = round(time.clock() - start_time, 2)print("2. Named Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

3)默认的itertuples()使用name=无更快,但并不方便,因为您必须为每列定义一个变量。

start_time = time.clock()result = 0for(_, col1, col2, col3, col4) in df.itertuples(name=None):result += max(col2, col3)
total_elapsed_time = round(time.clock() - start_time, 2)print("3. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

4)最后,命名的itertuples()比前一点慢,但您不必为每列定义一个变量,它适用于列名,例如My Col-Name is very Strange

start_time = time.clock()result = 0for row in df.itertuples(index=False):result += max(row[df.columns.get_loc('B')], row[df.columns.get_loc('C')])
total_elapsed_time = round(time.clock() - start_time, 2)print("4. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))

输出:

         A   B   C   D0       41  63  42  231       54   9  24  652       15  34  10   93       39  94  82  974        4  88  79  54...     ..  ..  ..  ..999995  48  27   4  25999996  16  51  34  28999997   1  39  61  14999998  66  51  27  70999999  51  53  47  99
[1000000 rows x 4 columns]
1. Iterrows done in 104.96 seconds, result = 661515192. Named Itertuples done in 1.26 seconds, result = 661515193. Itertuples done in 0.94 seconds, result = 661515194. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519

这篇文章是一个非常有趣的迭代和迭代的比较

更新:cs95已经更新了他的回答,加入了纯numpy向量化。你可以简单地参考他的回答。


cs95显示,Pandas矢量化远远优于其他Pandas方法,用于使用数据帧计算东西。

我想补充一点,如果你首先将数据框转换为NumPy数组,然后使用矢量化,它甚至比Pandas数据框矢量化更快(这包括将其转换回数据框系列的时间)。

如果您将以下函数添加到cs95的基准代码中,这变得非常明显:

def np_vectorization(df):np_arr = df.to_numpy()return pd.Series(np_arr[:,0] + np_arr[:,1], index=df.index)
def just_np_vectorization(df):np_arr = df.to_numpy()return np_arr[:,0] + np_arr[:,1]

在此处输入图片描述

总之

  • 如果可能,使用矢量化
  • 如果一个操作不能向量化-使用列表推导
  • 如果你需要一个代表整个行的对象-使用迭代
  • 如果上面的太慢-尝试swifter.apply
  • 如果它仍然太慢-尝试Cython例程

基准

熊猫数据帧中行的迭代基准

除了这篇文章中的伟大答案,我还将提出分裂与征服方法,我写这个答案不是为了废除其他伟大的答案,而是用另一种对我有效的方法来实现它们。它有splittingmerging熊猫数据框的两个步骤:

分而治之的好处:

  • 您不需要使用矢量化或任何其他方法将数据框的类型转换为另一种类型
  • 您不需要对代码进行Cython化,这通常需要额外的时间
  • 在我的例子中,iterrows()itertuples()在整个数据帧上具有相同的性能
  • 取决于你对切片index的选择,你将能够指数级地加快迭代。index越高,迭代过程越快。

分而治之的缺点:

  • 你不应该在迭代过程中依赖于相同的数据帧和不同的切片。这意味着如果你想从其他切片读取或写入,可能很难做到这一点。

===================分而治之的方法=================

步骤1:分割/切片

在这一步中,我们将在整个数据帧上划分迭代。假设你要将一个CSV文件读取到熊猫df中,然后迭代它。在可能的情况下,我有5,000,000条记录,我将把它分成100,000条记录。

注:我需要重申,正如本页其他解决方案中解释的其他运行时分析一样,“记录数量”在df上的搜索中具有“运行时”的指数比例。根据我的数据基准,这里是结果:

Number of records | Iteration rate [per second]========================================100,000           | 500500,000           | 2001,000,000         | 505,000,000         | 20

步骤2:合并

这将是一个简单的步骤,只需将所有写入的CSV文件合并到一个数据框中,并将其写入更大的CSV文件。

以下是示例代码:

# Step 1 (Splitting/Slicing)import pandas as pddf_all = pd.read_csv('C:/KtV.csv')df_index = 100000df_len = len(df)for i in range(df_len // df_index + 1):lower_bound = i * df_indexhigher_bound = min(lower_bound + df_index, df_len)# Splitting/slicing df (make sure to copy() otherwise it will be a viewdf = df_all[lower_bound:higher_bound].copy()'''Write your iteration over the sliced df hereusing iterrows() or intertuples() or ...'''# Writing into CSV filesdf.to_csv('C:/KtV_prep_' + str(i) + '.csv')


# Step 2 (Merging)filename = 'C:/KtV_prep_'df = (pd.read_csv(f) for f in [filename + str(i) + '.csv' for i in range(ktv_len // ktv_index + 1)])df_prep_all = pd.concat(df)df_prep_all.to_csv('C:/KtV_prep_all.csv')

参考:

在datafreame上迭代的有效方法

将CSV文件连接到一个Pandas Dataframe

最简单的方法,使用apply函数

def print_row(row):print row['c1'], row['c2']
df.apply(lambda row: print_row(row), axis=1)

正如这里的许多答案正确而明确地指出的那样,你通常不应该尝试在Pandas中循环,而是应该编写矢量化代码。但问题仍然是,你是否应该曾经在Pandas中编写循环,如果是,在这种情况下循环的最佳方式是什么。

我相信至少有一种适用于循环的一般情况:当你需要以某种复杂的方式计算一些依赖于其他行中的值的函数时。在这种情况下,循环代码通常比矢量化代码更简单、更具可读性且更不容易出错。循环代码甚至可能更快。

我将尝试用一个例子来展示这一点。假设您想获取一列的累积和,但当其他列等于零时重置它:

import pandas as pdimport numpy as np
df = pd.DataFrame( { 'x':[1,2,3,4,5,6], 'y':[1,1,1,0,1,1]  } )
#   x  y  desired_result#0  1  1               1#1  2  1               3#2  3  1               6#3  4  0               4#4  5  1               9#5  6  1              15

这是一个很好的例子,你当然可以写一行Pandas来实现这一点,尽管它不是特别可读,特别是如果你对Pandas还没有足够的经验:

df.groupby( (df.y==0).cumsum() )['x'].cumsum()

在大多数情况下,这将足够快,尽管您也可以通过避免groupby来编写更快的代码,但它的可读性可能会更低。

或者,如果我们把它写成一个循环呢?你可以用NumPy做如下事情:

import numba as nb
@nb.jit(nopython=True)  # Optionaldef custom_sum(x,y):x_sum = x.copy()for i in range(1,len(df)):if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i]return x_sum
df['desired_result'] = custom_sum( df.x.to_numpy(), df.y.to_numpy() )

诚然,将DataFrame列转换为NumPy数组需要一些开销,但核心代码只是一行代码,即使您对Pandas或NumPy一无所知,也可以阅读:

if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i]

这段代码实际上比向量化代码更快。在一些具有100,000行的快速测试中,上面的方法比Groupby方法快大约10倍。请注意,速度的一个关键是numba,这是可选的。如果没有“@nb.jit”行,循环代码实际上比Groupby方法慢大约10倍。

显然,这个例子很简单,你可能更喜欢一行熊猫而不是编写一个带有相关开销的循环。然而,这个问题还有更复杂的版本,NumPy/numba循环方法的易读性或速度可能是有意义的。

使用df.iloc[]。例如,使用数据框“rows_df”:

在此输入图片描述

要从特定行获取值,您可以将dataframe转换为ndarray。

然后像这样选择行和列值:

在此输入图片描述

公认的答案所述,在行上应用函数的最快方法是使用向量化函数,即所谓的NumPyufuncs(通用函数)。

但是,当您要应用的函数尚未在NumPy中实现时,您应该怎么办?

好吧,使用numba中的vectorize装饰器,您可以像这样轻松地直接在Python中创建ufuns:

from numba import vectorize, float64
@vectorize([float64(float64)])def f(x):#x is your line, do something with it, and return a float

这个函数的留档在这里:创建NumPy通用函数

df.iterrows()返回tuple(a, b),其中aindexbrow

可能是最优雅的解决方案(但肯定不是最有效的):

for row in df.values:c2 = row[1]print(row)# ...
for c1, c2 in df.values:# ...

注意:

  • 留档明确建议使用.to_numpy()代替
  • 生成的NumPy数组将具有适合所有列的dtype,在最坏的情况下object
  • 充分的理由不首先使用循环

尽管如此,我认为这个选项应该包括在这里,作为一个简单的解决方案(人们应该认为)琐碎的问题。

我们有多种选择来做同样的事情,很多人都分享了他们的答案。

我发现以下两种方法既简单又有效:

  1. DataFrame.iterrows()
  2. DataFrame.itertuples()

示例:

 import pandas as pdinp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]df = pd.DataFrame(inp)print (df)
# With the iterrows method
for index, row in df.iterrows():print(row["c1"], row["c2"])
# With the itertuples method
for row in df.itertuples(index=True, name='Pandas'):print(row.c1, row.c2)

注意:迭代组()应该比迭代组()更快

免责声明:虽然这里有很多答案推荐没有使用迭代(循环)方法(我基本同意),但我仍然认为它是以下情况的合理方法:

使用来自API的数据扩展数据框

假设您有一个包含不完整用户数据的大型数据框。现在您必须使用其他列扩展此数据,例如,用户的agegender

这两个值都必须从后端API获取。我假设API不提供“批处理”端点(它将一次接受多个用户ID)。否则,你应该只调用API一次。

到目前为止,网络请求的成本(等待时间)远远超过了数据帧的迭代。我们谈论的是数百毫秒的网络往返时间,而使用替代迭代方法的收益可以忽略不计。

每行一个昂贵的网络请求

所以在这种情况下,我绝对更喜欢使用迭代方法。尽管网络请求很昂贵,但它保证对数据帧中的每一行只触发一次。这是一个使用DataFrame.iterrows的例子:

示例

for index, row in users_df.iterrows():user_id = row['user_id']
# Trigger expensive network request once for each rowresponse_dict = backend_api.get(f'/api/user-data/{user_id}')
# Extend dataframe with multiple data from responseusers_df.at[index, 'age'] = response_dict.get('age')users_df.at[index, 'gender'] = response_dict.get('gender')