我有一只来自pandas的DataFrame
:
import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print df
输出:
c1 c2
0 10 100
1 11 110
2 12 120
现在我想迭代这个帧的行。对于每一行,我希望能够通过列的名称访问其元素(单元格中的值)。例如:
for row in df.rows:
print row['c1'], row['c2']
是否有可能在熊猫中做到这一点?
我发现了similar question。但它没有给我我需要的答案。例如,建议使用:
for date, row in df.T.iteritems():
或
for row in df.iterrows():
但我不明白row
对象是什么以及如何使用它。
答案 0 :(得分:1744)
DataFrame.iterrows是一个产生索引和行
的生成器for index, row in df.iterrows():
print(row['c1'], row['c2'])
Output:
10 100
11 110
12 120
答案 1 :(得分:270)
首先考虑一下你是否真的需要迭代来覆盖DataFrame中的行。有关替代方案,请参阅this answer。
如果仍需要遍历行,可以使用以下方法。请注意一些其他答案中未提及的重要警告。
for index, row in df.iterrows():
print row["c1"], row["c2"]
for row in df.itertuples(index=True, name='Pandas'):
print getattr(row, "c1"), getattr(row, "c2")
itertuples()
应该比iterrows()
但请注意,根据文档(目前的pandas 0.24.2):
iterrows:dtype
可能在行与行之间不匹配
因为iterrows为每一行返回一个Series,所以不会在行中保留 dtypes(dtypes在DataFrames的列之间保留)。为了在迭代行时保留dtypes,最好使用itertuples()返回值的namedtuples,它通常比iterrows快得多()
iterrows:不要修改行
您应该永远不会修改您正在迭代的内容。这并不能保证在所有情况下都有效。根据数据类型,迭代器返回一个副本而不是视图,写入它将不起作用。
改为使用DataFrame.apply():
new_df = df.apply(lambda x: x * 2)
itertuples:
如果列名称是无效的Python标识符,重复或以下划线开头,则列名称将重命名为位置名称。使用大量列(> 255),将返回常规元组。
有关详细信息,请参阅pandas docs on iteration。
答案 2 :(得分:140)
虽然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
答案 3 :(得分:78)
您还可以使用df.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)
答案 4 :(得分:66)
您可以按如下方式使用df.iloc函数:
for i in range(0, len(df)):
print df.iloc[i]['c1'], df.iloc[i]['c2']
答案 5 :(得分:34)
问:如何在Pandas中的DataFrame中遍历行?
大熊猫中的迭代是一种反模式,只有在穷尽所有其他可能选项后才应该这样做。您不应该考虑将名称中带有“ iter
”的任何功能用于数千行以上,否则您将不得不习惯很多的等待。
您要打印一个DataFrame吗?使用DataFrame.to_string()
。
您要计算一些东西吗?在这种情况下,请按以下顺序搜索方法(列表从here修改):
for
循环)DataFrame.apply()
DataFrame.itertuples()
和iteritems()
DataFrame.iterrows()
iterrows
和itertuples
(在此问题的答案中都获得很多选票)应在非常罕见的情况下使用,例如生成行对象/命名元以进行顺序处理,这实际上是唯一的选择这些功能非常有用。
向当局提出上诉
The docs page在迭代中有一个巨大的红色警告框,上面显示:
遍历熊猫对象通常很慢。在许多情况下,不需要手动对行进行迭代[...]。
大熊猫(通过NumPy或Cythonized函数)将“大量矢量化”了基本操作和计算。这包括算术,比较,(大多数)归约,整形(例如透视),联接和groupby操作。浏览Essential Basic Functionality上的文档以找到适合您问题的矢量化方法。
如果不存在,请随时使用自定义cython extensions编写自己的内容。
如果由于没有可用的向量化解决方案而进行迭代,并且性能很重要(但不足以使代码被cython化),则使用列表理解作为下一个最佳/最简单的选择。
要使用单个列遍历行,请使用
result = [f(x) for x in df['col']]
要遍历使用多列的行,可以使用
# two column format
result = [f(x, y) for x, y in zip(df['col1'], df['col2'])]
# many column format
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].values]
如果在迭代时需要整数行索引,请使用enumerate
:
result = [f(...) for i, row in enumerate(df[...].values)]
(其中df.index[i]
为您提供索引标签。)
如果可以将其转换为函数,则可以使用列表推导。您可以通过原始python的简单性和速度来使任意复杂的事情起作用。
答案 6 :(得分:26)
我一直在寻找如何对行和列进行迭代,并在此结束:
for i, row in df.iterrows():
for j, column in row.iteritems():
print(column)
答案 7 :(得分:15)
您可以编写自己的迭代器来实现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
直接相当。我的目标是以更高的效率执行相同的任务。
对于具有my function的给定数据帧:
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);
答案 8 :(得分:13)
要循环dataframe
中的所有行,您可以使用:
for x in range(len(date_example.index)):
print date_example['Date'].iloc[x]
答案 9 :(得分:12)
const
答案 10 :(得分:7)
有时候有用的模式是:
# Borrowing @KutalmisB df example
df = 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 row
for row_dict in df.to_dict(orient='records'):
print(row_dict)
这将导致:
{'col1':1.0, 'col2':0.1}
{'col1':2.0, 'col2':0.2}
答案 11 :(得分:6)
要循环<{1}}和使用每行的所有行方便,dataframe
可以转换为namedtuples
秒。例如:
ndarray
迭代行:
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]
,将索引添加为元组的第一个元素,这对某些应用程序可能不合适。
答案 12 :(得分:6)
简而言之
答案 13 :(得分:6)
cs95 shows,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]
答案 14 :(得分:4)
有一种方法可以在返回DataFrame而不是Series的同时迭代引发行。我没有看到任何人提到您可以将index作为列表传递给要作为DataFrame返回的行:
for i in range(len(df)):
row = df.iloc[[i]]
请注意双括号的用法。这将返回一个具有单行的DataFrame。
答案 15 :(得分:2)
最简单的方法是使用apply
函数
def print_row(row):
print row['c1'], row['c2']
df.apply(lambda row: print_row(row), axis=1)
答案 16 :(得分:2)
我试图弄清楚如何通过熊猫数据框有效地进行迭代。有不同的方法,通常的iterrows()远非最佳。 itertuples()可以快100倍。
df = pd.DataFrame(np.random.randint(0, 100, size=(1000000, 4)), columns=list('ABCD'))
print(df)
1)iterrows()
很方便,但是该死的很慢
start_time = time.clock()
result = 0
for _, 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()
已经快了
start_time = time.clock()
result = 0
for 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()
start_time = time.clock()
result = 0
for row in df.itertuples():
result += max(getattr(row, "B"), getattr(row, "C"))
total_elapsed_time = round(time.clock() - start_time, 2)
print("3. Named Itertuples using getattr done in {} seconds, result = {}".format(total_elapsed_time, result))
4)使用name = None的默认itertuples()
更快
start_time = time.clock()
result = 0
for(_, col1, col2, col3, col4) in df.itertuples(name=None):
result += max(col2, col3)
total_elapsed_time = round(time.clock() - start_time, 2)
print("4. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))
5)命名为itertuples()
的列名,例如My Col-Name is very Strange
start_time = time.clock()
result = 0
for 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("5. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))
输出:
A B C D
0 41 63 42 23
1 54 9 24 65
2 15 34 10 9
3 39 94 82 97
4 4 88 79 54
... .. .. .. ..
999995 48 27 4 25
999996 16 51 34 28
999997 1 39 61 14
999998 66 51 27 70
999999 51 53 47 99
[1000000 rows x 4 columns]
1. Iterrows done in 104.96 seconds, result = 66151519
2. Named Itertuples done in 1.26 seconds, result = 66151519
3. Named Itertuples using getattr done in 1.56 seconds, result = 66151519
4. Itertuples done in 0.94 seconds, result = 66151519
5. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519
This article is a very interesting comparison between iterrows and itertuples
总结:
df.itertuples(name=None)
df.itertuples()
否则,除非您的列中有特殊字符(''或'-',)itertuples()
。iterrows()
答案 17 :(得分:1)
df.iterrows() 返回元组(a,b),其中 a 是索引,b 是行。
答案 18 :(得分:1)
在这篇文章中,除了很好的答案,我将提出 Divide and Conquer 方法,我不是为了消除其他好的答案而写这个答案,而是通过另一种可行的方法来实现它们对我有效。它有两个步骤splitting
和merging
熊猫数据框:
分而治之的优势:
iterrows()
和itertuples()
在整个数据帧上的性能相同index
的选择,您将能够以指数方式加快迭代速度。 index
越高,迭代过程越快。分而治之的缺点:
===================分而治之=================
步骤1:拆分/切片
在此步骤中,我们将在整个数据帧上划分迭代。认为您将要读取csv文件到pandas df中,然后对其进行遍历。在可能的情况下,我有5,000,000条记录,我打算将其拆分为100,000条记录。
注意::我需要重申,正如本页其他解决方案中所述的其他运行时分析一样,在df上搜索时,“记录数”与“运行时”成指数比例。根据基准数据,得出以下结果:
Number of records | Iteration per second
========================================
100,000 | 500 it/s
500,000 | 200 it/s
1,000,000 | 50 it/s
5,000,000 | 20 it/s
第2步:合并
这将是一个简单的步骤,只需将所有写入的csv文件合并到一个数据帧中,然后将其写入更大的csv文件中即可。
这是示例代码:
# Step 1 (Splitting/Slicing)
import pandas as pd
df_all = pd.read_csv('C:/KtV.csv')
df_index = 100000
df_len = len(df)
for i in range(df_len // df_index + 1):
lower_bound = i * df_index
higher_bound = min(lower_bound + df_index, df_len)
# splitting/slicing df (make sure to copy() otherwise it will be a view
df = df_all[lower_bound:higher_bound].copy()
'''
write your iteration over the sliced df here
using iterrows() or intertuples() or ...
'''
# writing into csv files
df.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')
参考:
答案 19 :(得分:1)
此示例使用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])
答案 20 :(得分:1)
有很多方法可以遍历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 column
print(df.iloc[i,1])
# For printing more than one columns
print(df.iloc[i,[0,2]])
答案 21 :(得分:1)
您还可以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
答案 22 :(得分:0)
只需加上我的两分钱,
正如公认的答案所述,对行应用函数的最快方法是使用向量化函数,即所谓的 numpy ufuncs
(通用函数)
但是如果您要应用的功能尚未在 numpy
中实现,您应该怎么做?
使用 vectorize
中的 numba
装饰器,您可以像这样直接在 Python 中轻松创建 ufunc:
from numba import vectorize, float64
@vectorize([float64(float64)])
def f(x):
#x is your line, do something with it, and return a float
此函数的文档在这里:https://numba.pydata.org/numba-doc/latest/user/vectorize.html
答案 23 :(得分:0)
对于查看和修改值,我将使用iterrows()
。在for循环中,通过使用元组拆包(请参见示例:i, row
),我使用row
仅查看值,并在情况下将i
与loc
方法一起使用我想修改值。如先前的答案所述,您不应在此处修改要迭代的内容。
for i, row in df.iterrows():
if row['A'] == 'Old_Value':
df.loc[i,'A'] = 'New_value'
此处循环中的row
是该行的副本,而不是它的视图。因此,您不应编写类似row['A'] = 'New_Value'
的内容,它不会修改DataFrame。但是,您可以使用i
和loc
并指定DataFrame来完成工作。
答案 24 :(得分:0)
答案 25 :(得分:0)
正如这里的许多答案正确且清楚地指出的那样,您通常不应该尝试在 Pandas 中循环,而应该编写矢量化代码。但是问题仍然存在,你是否应该永远在 Pandas 中编写循环,如果是这样,在这些情况下循环的最佳方式。
我相信至少有一种适合循环的一般情况:当您需要以某种复杂的方式计算依赖于其他行中的值的某个函数时。在这种情况下,循环代码通常比向量化代码更简单、更易读且不易出错。循环代码甚至可能更快。
我将尝试用一个例子来说明这一点。假设您想获取一列的累积总和,但在其他列为零时重置它:
import pandas as pd
import 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) # Optional
def 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 一无所知,也可以阅读:< /p>
if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i]
而且这段代码实际上比矢量化代码更快。在一些 100,000 行的快速测试中,上述方法比 groupby 方法快 10 倍左右。请注意,速度的一个关键是numba,即选项。如果没有“@nb.jit”行,循环代码实际上比 groupby 方法慢 10 倍。
显然这个例子很简单,你可能更喜欢一行pandas而不是编写一个带有相关开销的循环。然而,这个问题还有更复杂的版本,NumPy/numba 循环方法的可读性或速度可能更有意义。
答案 26 :(得分:0)
某些库(例如,我使用的Java互操作库)要求一次将值连续传递,例如,如果要流式传输数据。为了复制流式传输的特性,我逐一“流式传输”我的数据帧值,我写了下面的内容,它有时会派上用场。
class DataFrameReader:
def __init__(self, df):
self._df = df
self._row = None
self._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 += 1
return 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 0
try:
if type(key) is list:
ix = [self._columns.index(key) + 1 for k in key]
else:
ix = self._columns.index(key) + 1
return self._row[ix]
except BaseException as e:
return None
def __next__(self) -> 'DataFrameReader':
if self.read():
return self
else:
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())
并保留要迭代的行的值/名称映射。显然,这比使用如上所述的apply和Cython慢很多,但是在某些情况下是必需的。
答案 27 :(得分:-1)
可能是最优雅的解决方案(但肯定不是最有效的):
for row in df.values:
c2 = row[1]
print(row)
# ...
for c1, c2 in df.values:
# ...
注意:
.to_numpy()
object
不过,我认为这个选项应该包括在这里,作为一个(应该认为)微不足道的问题的直接解决方案。
答案 28 :(得分:-2)
为什么使事情复杂化?
简单。
import pandas as pd
import numpy as np
# Here is an example dataframe
df_existing = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))
for idx,row in df_existing.iterrows():
print row['A'],row['B'],row['C'],row['D']