关于python:如何在pandas中迭代数据帧中的行?

How to iterate over rows in a DataFrame in Pandas?

我有一个大熊猫的DataFrame

1
2
3
4
import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print df

输出:

1
2
3
4
   c1   c2
0  10  100
1  11  110
2  12  120

现在我想迭代这个框架的行。对于每一行,我希望能够通过列的名称访问其元素(单元格中的值)。例如:

1
2
for row in df.rows:
   print row['c1'], row['c2']

在熊猫身上可以这样做吗?

我发现了类似的问题。但它没有给我所需要的答案。例如,建议使用:

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

1
for row in df.iterrows():

但我不明白row的目标是什么,以及如何使用它。

  • df.iteritems()迭代列而不是行。因此,要使它在行上迭代,必须转置("t"),这意味着要将行和列相互更改(在对角线上反射)。因此,当使用df.t.iteritems()时,可以有效地在原始数据帧的行上迭代。
  • 如果你是这个线程的新手,并且是熊猫的初学者,不要重复!!在数据帧上迭代是一种反模式,除非你想适应很多等待,否则你不应该这样做。根据你想做什么,可能有更好的选择。iter*函数应在极少数情况下使用。也相关。


ITerRows是一个生成索引和行的生成器。

1
2
3
4
5
6
7
for index, row in df.iterrows():
    print(row['c1'], row['c2'])

Output:
   10 100
   11 110
   12 120

  • 注意:"因为ITerRows为每一行返回一个序列,所以它不保留跨行的数据类型。"此外,"您不应该修改正在迭代的内容。"根据Pandas 0.19.1文档
  • @维迪克13这是一个很好的音符,谢谢。因为这个原因,我遇到了一个例子,在这个例子中,像431341610650这样的数值读取为4.31E+11。有没有办法保存数据类型?
  • @阿齐扎尔托使用itertuples,如下所述。另请参见pandas.pydata.org/pandas docs/stable/generated/…
  • 如果在迭代时不使用索引变量,那么row对象将如何更改??在这种情况下,我们必须使用行[0],行[1]而不是标签?
  • 不要使用箭头。ITertuples速度更快并保留数据类型。更多信息
  • 如果不需要保留数据类型,ITerRows就可以了。@waitingkuo分离索引的提示使解析更容易。


要在pandas中迭代数据帧的行,可以使用:

  • 数据帧.iterrows()。

    1
    2
    for index, row in df.iterrows():
        print row["c1"], row["c2"]
  • 数据帧.itertuples()。

    1
    2
    for row in df.itertuples(index=True, name='Pandas'):
        print getattr(row,"c1"), getattr(row,"c2")

itertuples()应该比iterrows()快。

但请注意,根据文件(目前熊猫0.21.1):

  • i错误:dtype可能在行与行之间不匹配。


    Because iterrows returns a Series for each row, it does not preserve dtypes across the rows (dtypes are preserved across columns for DataFrames).

  • ITerRows:不修改行


    You should never modify something you are iterating over. This is not guaranteed to work in all cases. Depending on the data types, the iterator returns a copy and not a view, and writing to it will have no effect.

    改用dataframe.apply():

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


    The column names will be renamed to positional names if they are invalid Python identifiers, repeated, or start with an underscore. With a large number of columns (>255), regular tuples are returned.

  • 在这个线程完成后这么长时间阅读它的人提出了一个小问题:df.apply()如何在效率方面与ITertuples进行比较?
  • 注意:您也可以说像for row in df[['c1','c2']].itertuples(index=True, name=None):这样的话,只在行迭代器中包含某些列。
  • 您可以只使用row.c1,而不是getattr(row,"c1")
  • 我大约90%的人相信,如果你使用getattr(row,"c1")而不是row.c1,你会失去itertuples的任何性能优势,如果你真的需要通过一个字符串来访问属性,你应该使用iterrow。
  • 当我尝试这样做时,它只打印列值,而不打印标题。列标题是否从行属性中排除?


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

1
2
3
4
5
6
7
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

  • 两个示例中的大部分时间差异似乎是由于您似乎正在使用基于标签的索引来执行.iterrows()命令,而使用基于整数的索引来执行.itertuples()命令。
  • 对于基于财务数据的数据帧(时间戳和4x浮点),ITertuples比我的机器上的ITerRows快19.57倍。只有for a,b,c in izip(df["a"],df["b"],df["c"]:的速度几乎一样快。
  • 你能解释一下为什么它更快吗?
  • @abemiessler-iterrows()将每一行数据框成一个系列,而itertuples()则不这样做。
  • 注意,列的顺序实际上是不确定的,因为df是从字典创建的,所以row[1]可以引用任何列。结果表明,整数与浮点数列的时间大致相同。
  • @杰斐尔,你引用的时间是完全一样的,怎么可能呢?另外,当我提到基于整数的索引时,我的意思类似row.iat[1]。
  • @亚历克斯看起来确实很可疑。我只是重新扫描了几次,它的时间比它长了3倍。大熊猫0.23.4。将删除其他注释以避免混淆。
  • 然后在一个更大的数据框架上运行,更像现实世界中的情况,iTertuples比iTerrows快100倍。我为胜利而努力。
  • 我得到了一个大于50倍的增长以及i.stack.imgur.com/hbe9o.png(在第二次运行中改为attr访问器)。


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

文档:dataframe.apply())

1
2
3
4
def valuation_formula(x, y):
    return x * y * 0.5

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

  • df[‘price’]是否指数据框中的列名?我正在尝试用csv文件中的几个列中的唯一值创建字典。我使用您的逻辑创建了一个具有唯一键和值的字典,并得到了一个声明typeerror的错误:("series"对象是可变的,因此不能散列,"u"出现在索引0')
  • 代码:df['workclass']=df.apply(lambda行:dic_update(row),轴=1)行末id=0行末def dic_update(row):如果行不在dic中:dic[row]=id id=id+1
  • 没关系,我知道了。将函数调用行更改为df_new=df['workclass']。
  • 才华横溢,做了我想做的,最后教我使用apply!
  • 轴默认为0是最差的
  • 请注意,apply不会对行进行"迭代",而是应用一个逐行的函数。如果您确实需要迭代和优柔寡断,例如在跨行比较值时(在这种情况下,除了迭代之外,您什么都不能做),上面的代码将不起作用。
  • 这绝对比使用ITerRows好。不幸的是,这仍然不是一个好建议。


您可以使用df.iloc函数,如下所示:

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

  • range中使用0是没有意义的,可以省略它。
  • 我知道一个人应该避免这样的事情,而应该支持iTerrows或iTertuples,但是知道为什么会很有趣。有什么想法吗?
  • 这是我知道的唯一有效的方法,如果您想保留数据类型,也可以按名称引用列。itertuples保留了数据类型,但去掉了它不喜欢的任何名称。iterrows的作用正好相反。
  • 花了数小时的时间,试图通过熊猫数据结构的特性来做一些简单而富有表现力的事情。这会产生可读的代码。
  • 虽然for i in range(df.shape[0])可能会加快这种方法的速度,但对于我的应用程序来说,它仍然比上面的iterrows()方法慢3.5倍。
  • 在大型数据库中,这似乎更好,因为my_iter = df.itertuples()需要双倍的内存和大量的时间来复制它。同iterrows()
  • 这是链接索引。不要使用!


我在寻找如何在行和列上迭代,并在这里结束,因此:

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

  • 对行进行迭代已经足够糟糕了。你到底为什么要这么做?


使用itertuples()。它比ITerRows()快:

1
2
for row in df.itertuples():
    print"c1 :",row.c1,"c2 :",row.c2

  • 我看不出这个答案是如何添加以前答案中没有的内容的。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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相当。我的目标是以更高的效率完成同样的任务。

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

1
2
3
list(myiter(df))

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

或与pd.DataFrame.itertuples一起:

1
2
3
list(df.itertuples(index=False))

[Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]

综合测试我们测试使所有列都可用,并对这些列进行子集设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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);

enter image description here

enter image description here

  • 对于不想阅读代码的人:蓝线是intertuples,橙线是一个通过yield块的迭代器列表。不比较interrows


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

1
2
for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]

  • 这是链接索引。我不建议这样做。
  • @CS95你会推荐什么?
  • 如果要使其正常工作,请调用df.columns.get_loc以获取日期列的整数索引位置(循环外部),然后在内部使用单个ILOC索引调用。


Q: How to iterate over rows in a DataFrame in Pandas?

不要!

大熊猫的迭代是一种反模式,只有当你用尽了所有其他可能的选择时,你才应该做些什么。对于超过几千行的内容,您不应该考虑在其名称中使用任何带有"iter"的函数,否则您将不得不习惯于大量等待。

是否要打印数据帧?使用DataFrame.to_string()

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

  • 矢量化
  • 塞隆例程
  • 列表理解(for循环)
  • DataFrame.apply()i.可以在赛通中进行的减少二。在python空间中迭代
  • DataFrame.itertuples()iteritems()
  • DataFrame.iterrows()
  • iterrowsitertuples在极少数情况下都应该使用(这两个问题的答案都获得了许多选票),例如生成行对象/名称元组进行顺序处理,这些功能都很擅长。

    向当局上诉迭代的docs页面有一个巨大的红色警告框,上面写着:

    Iterating through pandas objects is generally slow. In many cases, iterating manually over the rows is not needed [...].

    比循环更快:矢量化,赛通

    大量的基本操作和计算是由熊猫"矢量化"的(通过numpy或通过cythonized函数)。这包括算术、比较(大多数)、约简、重塑(如旋转)、联接和分组操作。查看有关基本功能的文档,为您的问题找到合适的矢量化方法。

    如果不存在,可以使用自定义的Cython扩展自行编写。

    其次是:列出理解

    如果您正在迭代,因为没有可用的矢量化解决方案,并且性能很重要(但还不够重要,无法解决代码的网络化问题),那么使用列表理解作为下一个最佳/最简单的选项。

    要使用单列迭代行,请使用

    1
    result = [f(x) for x in df['col']]

    要使用多个列在行上迭代,可以使用

    1
    2
    3
    4
    5
    # 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

    1
    result = [f(...) for i, row in enumerate(df[...].values)]

    (其中df.index[i]为您提供索引标签。)

    如果你能把它变成一个函数,你可以使用列表理解。您可以通过原始Python的简单性和速度使任意复杂的事情工作。

    • 超级,谢谢。


    imho,最简单的决定

    1
    2
     for ind in df.index:
         print df['c1'][ind], df['c2'][ind]

    • 在大型数据帧(例如数百万行)上使用时,此选项的性能如何?
    • 老实说,我不太清楚,我认为与最佳答案相比,所用的时间将大致相同,因为这两种情况都使用"for"-构造。但在某些情况下,记忆可能会有所不同。
    • 这是链接索引。不要用这个!


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

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

    遍历行:

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

    结果:

    1
    2
    [ 1.   0.1]
    [ 2.   0.2]

    请注意,如果index=True,则添加索引作为元组的第一个元素,这可能不适合某些应用程序。


    有时一个有用的模式是:

    1
    2
    3
    4
    5
    6
    # 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)

    结果是:

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

    为什么事情复杂化?

    简单。

    1
    2
    3
    4
    5
    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'))
    1
    2
    for idx,row in df_existing.iterrows():
        print row['A'],row['B'],row['C'],row['D']

    • 这与公认的答案有何不同??
    • 我想我更喜欢当编码人员可以快速地截取整个代码块运行它,它可以很好地解析。接受的答案需要拼凑块。限时器


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

    1
    2
    3
    4
    5
    6
    7
    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]])

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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])


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

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

    您也可以将其强制转换为数组。这些索引/选择应该已经像numpy数组一样工作了,但我遇到了问题,需要强制转换

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

    对于查看和修改值,我将使用iterrows()。在for循环中,通过使用tuple解包(参见示例:i, row,我只使用row查看值,当我想修改值时,使用iloc方法。如前面的答案所述,这里不应该修改您正在迭代的内容。

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

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