Làm cách nào để lặp lại qua các hàng trong DataFrame trong Pandas?


1951

Tôi có một DataFrametừ gấu trúc:

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

Đầu ra:

   c1   c2
0  10  100
1  11  110
2  12  120

Bây giờ tôi muốn lặp lại các hàng của khung này. Đối với mỗi hàng tôi muốn có thể truy cập các phần tử của nó (giá trị trong các ô) theo tên của các cột. Ví dụ:

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

Có thể làm điều đó trong gấu trúc?

Tôi tìm thấy câu hỏi tương tự này . Nhưng nó không cho tôi câu trả lời tôi cần. Ví dụ, nó được đề xuất sử dụng:

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

hoặc là

for row in df.iterrows():

Nhưng tôi không hiểu rowđối tượng là gì và làm thế nào tôi có thể làm việc với nó.


11
Df.iteritems () lặp trên các cột và không phải hàng. Do đó, để làm cho nó lặp đi lặp lại trên các hàng, bạn phải hoán vị ("T"), có nghĩa là bạn thay đổi các hàng và cột thành nhau (phản chiếu qua đường chéo). Kết quả là, bạn lặp lại hiệu quả khung dữ liệu gốc trên các hàng của nó khi bạn sử dụng df.T.iteritems ()
Stefan Gruenwald

12
Nếu bạn chưa quen với chủ đề này và là người mới bắt đầu chơi gấu trúc, ĐỪNG BỎ QUA !! Lặp lại trên dataframes là một mô hình chống và điều bạn không nên làm trừ khi bạn muốn làm quen với nhiều sự chờ đợi. Tùy thuộc vào những gì bạn đang cố gắng làm, có thể có những lựa chọn thay thế tốt hơn nhiều . iter*chức năng nên được sử dụng trong trường hợp rất hiếm. Cũng liên quan .
cs95

19
Trái ngược với những gì cs95 nói, có những lý do hoàn toàn chính xác để muốn lặp lại trên một khung dữ liệu, vì vậy người dùng mới không nên cảm thấy nản lòng. Một ví dụ là nếu bạn muốn thực thi một số mã bằng cách sử dụng các giá trị của mỗi hàng làm đầu vào. Ngoài ra, nếu khung dữ liệu của bạn nhỏ một cách hợp lý (ví dụ dưới 1000 mục), hiệu suất không thực sự là một vấn đề.
oulenz

1
@oulenz: Nếu vì một lý do kỳ quặc nào đó mà bạn muốn bay khi sử dụng API cho mục đích mà nó được thiết kế cho (chuyển đổi dữ liệu hiệu suất cao), thì hãy là khách của tôi. Nhưng ít nhất, đừng sử dụng iterrows, có nhiều cách tốt hơn để lặp lại trên DataFrame, bạn cũng có thể chỉ lặp lại một danh sách các danh sách tại thời điểm đó. Nếu bạn đang ở điểm mà bạn không làm gì ngoài việc lặp lại trên DataFrames, thì thực sự không có ích gì khi sử dụng DataFrame cả (giả sử lặp đi lặp lại đó là điều duy nhất bạn đang làm với nó). Chỉ cần 2c của tôi.
cs95

8
Tôi thứ hai @oulenz. Theo như tôi có thể nói pandaslà lựa chọn đọc tệp csv ngay cả khi tập dữ liệu nhỏ. Đơn giản là việc lập trình dễ dàng hơn để thao tác dữ liệu bằng API
Chris

Câu trả lời:


2638

DataFrame.iterrows là một trình tạo mang lại cả chỉ mục và hàng

import pandas as pd
import numpy as np

df = pd.DataFrame([{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}])

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

Output: 
   10 100
   11 110
   12 120

207
Lưu ý: "Vì iterrows trả về Sê-ri cho mỗi hàng, nên nó không bảo toàn các ký tự trên các hàng." Ngoài ra, "Bạn không bao giờ nên sửa đổi một cái gì đó bạn đang lặp đi lặp lại." Theo tài liệu gấu trúc 0.19.1
viddik13

3
@ viddik13 đó là một ghi chú tuyệt vời cảm ơn. Do đó, tôi gặp phải trường hợp giá trị số như 431341610650đọc ở đâu 4.31E+11. Có cách nào xung quanh việc bảo quản các dtypes?
Aziz Alto

26
@AzizAlto sử dụng itertuples, như được giải thích dưới đây. Xem thêm pandas.pydata.org/pandas-docs/urdy/generated/ Kẻ
Axel

101
Không sử dụng lặp. Itertuples nhanh hơn và bảo tồn kiểu dữ liệu. Thêm thông tin
James L.

11
Từ tài liệu : "Lặp lại thông qua các đối tượng gấu trúc nói chung là chậm. Trong nhiều trường hợp, việc lặp lại thủ công qua các hàng là không cần thiết [...]". Câu trả lời của bạn là chính xác (trong ngữ cảnh của câu hỏi) nhưng không đề cập đến vấn đề này ở bất cứ đâu, vì vậy nó không phải là một câu hỏi hay.
cs95

460

Làm cách nào để lặp lại qua các hàng trong DataFrame trong Pandas?

Trả lời: KHÔNG * !

Lặp lại trong gấu trúc là một mô hình chống, và là điều bạn chỉ nên làm khi bạn đã hết tất cả các lựa chọn khác. Bạn không nên sử dụng bất kỳ chức năng nào có " iter" trong tên của nó trong hơn một vài nghìn hàng hoặc bạn sẽ phải làm quen với rất nhiều sự chờ đợi.

Bạn có muốn in DataFrame không? Sử dụng DataFrame.to_string().

Bạn có muốn tính toán một cái gì đó? Trong trường hợp đó, tìm kiếm các phương thức theo thứ tự này (danh sách được sửa đổi từ đây ):

  1. Vector hóa
  2. Thói quen của Cython
  3. Danh sách hiểu ( forvòng vanilla )
  4. DataFrame.apply(): i) Việc giảm có thể được thực hiện trong cython, ii) Lặp lại trong không gian python
  5. DataFrame.itertuples()iteritems()
  6. DataFrame.iterrows()

iterrowsitertuples(cả hai nhận được nhiều phiếu trong câu trả lời cho câu hỏi này) nên được sử dụng trong các trường hợp rất hiếm, chẳng hạn như tạo các đối tượng hàng / bảng tên để xử lý tuần tự, đây thực sự là điều duy nhất các hàm này hữu ích.

Khiếu nại với chính quyền
Trang tài liệu về Lặp lại có một hộp cảnh báo màu đỏ rất lớn có nội dung:

Lặp lại thông qua các đối tượng gấu trúc nói chung là chậm. Trong nhiều trường hợp, việc lặp lại thủ công qua các hàng là không cần thiết [...].

* Nó thực sự phức tạp hơn một chút so với "không". df.iterrows()là câu trả lời chính xác cho câu hỏi này, nhưng "vectorize ops của bạn" là câu trả lời tốt hơn. Tôi sẽ thừa nhận rằng có những trường hợp không thể tránh được việc lặp lại (ví dụ: một số thao tác trong đó kết quả phụ thuộc vào giá trị được tính cho hàng trước đó). Tuy nhiên, phải mất một số quen thuộc với thư viện để biết khi nào. Nếu bạn không chắc chắn liệu bạn có cần một giải pháp lặp đi lặp lại hay không, có lẽ bạn không nên. PS: Để biết thêm về lý do của tôi khi viết câu trả lời này, hãy bỏ qua đến tận cùng.


Nhanh hơn Looping: Vectorization , Cython

Một số lượng lớn các hoạt động và tính toán cơ bản được "véc tơ" bởi gấu trúc (thông qua NumPy hoặc thông qua các hàm Cythonized). Điều này bao gồm số học, so sánh, giảm (hầu hết), định hình lại (chẳng hạn như xoay vòng), tham gia và hoạt động nhóm. Xem qua các tài liệu về Essential Basic Functionality để tìm ra một phương pháp vector hóa phù hợp cho vấn đề của bạn.

Nếu không tồn tại, vui lòng tự viết bằng các tiện ích mở rộng cython tùy chỉnh .


Điều tốt nhất tiếp theo: Danh sách toàn diện *

Việc hiểu danh sách sẽ là cổng gọi tiếp theo của bạn nếu 1) không có giải pháp véc tơ khả dụng, 2) hiệu suất rất quan trọng, nhưng không đủ quan trọng để vượt qua rắc rối của việc mã hóa mã của bạn và 3) bạn đang cố gắng thực hiện chuyển đổi theo yếu tố trên mã của bạn. Có một lượng bằng chứng tốt để đề xuất rằng việc hiểu danh sách là đủ nhanh (và thậm chí đôi khi nhanh hơn) cho nhiều nhiệm vụ gấu trúc thông thường.

Công thức rất đơn giản,

# iterating over one column - `f` is some function that processes your data
result = [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 type
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].to_numpy()]
# iterating over multiple columns - differing data type
result = [f(row[0], ..., row[n]) for row in zip(df['col1'], ..., df['coln'])]

Nếu bạn có thể gói logic logic kinh doanh của mình vào một hàm, bạn có thể sử dụng một cách hiểu danh sách gọi nó. Bạn có thể làm cho những thứ phức tạp tùy ý hoạt động thông qua sự đơn giản và tốc độ của trăn thô.

Việc
hiểu danh sách Caveats cho rằng dữ liệu của bạn dễ làm việc - điều đó có nghĩa là loại dữ liệu của bạn nhất quán và bạn không có NaN, nhưng điều này không thể luôn được đảm bảo.

  1. Cách thứ nhất thì rõ ràng hơn, nhưng khi giao dịch với NaN, hãy thích các phương pháp gấu trúc dựng sẵn nếu chúng tồn tại (vì chúng có logic xử lý tình huống góc tốt hơn nhiều) hoặc đảm bảo logic nghiệp vụ của bạn bao gồm logic xử lý NaN thích hợp.
  2. Khi xử lý các loại dữ liệu hỗn hợp, bạn nên lặp đi lặp lại zip(df['A'], df['B'], ...)thay vì df[['A', 'B']].to_numpy()kiểu sau sẽ ngầm định dữ liệu thành loại phổ biến nhất. Ví dụ nếu A là số và B là chuỗi, to_numpy()sẽ truyền toàn bộ mảng thành chuỗi, đây có thể không phải là điều bạn muốn. May mắn là zipping các cột của bạn với nhau là cách giải quyết đơn giản nhất cho việc này.

* YMMV vì những lý do được nêu trong phần Caveats ở trên.


Một ví dụ rõ ràng

Hãy chứng minh sự khác biệt bằng một ví dụ đơn giản về việc thêm hai cột gấu trúc A + B. Đây là một toán hạng có thể vector hóa, vì vậy nó sẽ dễ dàng tương phản hiệu suất của các phương pháp được thảo luận ở trên.

nhập mô tả hình ảnh ở đây

Mã điểm chuẩn, để bạn tham khảo.

Tôi nên đề cập, tuy nhiên, nó không phải lúc nào cũng bị cắt và khô. Đôi khi, câu trả lời cho "phương pháp tốt nhất cho hoạt động" là "nó phụ thuộc vào dữ liệu của bạn". Lời khuyên của tôi là thử nghiệm các cách tiếp cận khác nhau trên dữ liệu của bạn trước khi giải quyết một.


Đọc thêm

* Các phương thức chuỗi Pandas được "vector hóa" theo nghĩa là chúng được chỉ định trên chuỗi nhưng hoạt động trên từng phần tử. Các cơ chế cơ bản vẫn còn lặp đi lặp lại, bởi vì các hoạt động chuỗi vốn đã khó để vector hóa.


Tại sao tôi viết câu trả lời này

Một xu hướng phổ biến mà tôi nhận thấy từ những người dùng mới là đặt câu hỏi theo mẫu "làm thế nào tôi có thể lặp lại trên df của mình để làm X?". Hiển thị mã gọi iterrows()trong khi thực hiện một cái gì đó bên trong một vòng lặp for. Đây là lý do tại sao. Một người dùng mới vào thư viện chưa được giới thiệu về khái niệm vector hóa sẽ có khả năng hình dung mã giải quyết vấn đề của họ khi lặp lại dữ liệu của họ để làm gì đó. Không biết làm thế nào để lặp lại trên DataFrame, điều đầu tiên họ làm là Google nó và kết thúc ở đây, tại câu hỏi này. Sau đó, họ thấy câu trả lời được chấp nhận cho họ biết làm thế nào, và họ nhắm mắt lại và chạy mã này mà không bao giờ đặt câu hỏi đầu tiên nếu việc lặp lại không phải là điều đúng đắn.

Mục đích của câu trả lời này là giúp người dùng mới hiểu rằng lặp đi lặp lại không nhất thiết là giải pháp cho mọi vấn đề và các giải pháp tốt hơn, nhanh hơn và thành ngữ hơn có thể tồn tại và đáng để đầu tư thời gian để khám phá chúng. Tôi không cố bắt đầu cuộc chiến lặp lại so với vector hóa, nhưng tôi muốn người dùng mới được thông báo khi phát triển giải pháp cho các vấn đề của họ với thư viện này.


24
Đây là câu trả lời duy nhất tập trung vào các kỹ thuật thành ngữ mà người ta nên sử dụng với gấu trúc, làm cho nó trở thành câu trả lời tốt nhất cho câu hỏi này. Học để có câu trả lời đúng với đúng (thay vì trả lời đúng với sai - tức là không hiệu quả, không có quy mô, quá phù hợp với dữ liệu cụ thể) là một phần lớn của việc học gấu trúc (và dữ liệu nói chung).
LinkBerest

3
Tôi nghĩ rằng bạn đang không công bằng cho vòng lặp for, mặc dù, nhìn thấy vì chúng chỉ chậm hơn một chút so với việc hiểu danh sách trong các bài kiểm tra của tôi. Bí quyết là lặp đi lặp lại zip(df['A'], df['B'])thay vì df.iterrows().
Đêm vô thường

2
@ImperishableNight Không hề; mục đích của bài viết này không phải là để tố cáo việc lặp đi lặp lại nói chung - đó là để tố cáo cụ thể việc sử dụng iterrows()và ngầm định tố cáo việc lặp lại nếu và khi có sự thay thế tốt hơn. forBản thân các vòng lặp đều ổn, nhưng việc hiểu danh sách sẽ tốt hơn nếu bạn lặp đi lặp lại thực hiện các phép biến đổi thành phần.
cs95

1
@sdbbs có, sử dụng sort_values ​​để sắp xếp dữ liệu của bạn, sau đó gọi to_opes () trên kết quả.
cs95

1
Trong Danh sách hiểu, ví dụ "lặp qua nhiều cột" cần một cảnh báo: DataFrame.valuessẽ chuyển đổi mỗi cột thành một loại dữ liệu chung. DataFrame.to_numpy()cũng làm điều này May mắn thay chúng ta có thể sử dụng zipvới bất kỳ số lượng cột.
David Wasserman

397

Trước tiên hãy xem xét nếu bạn thực sự cần lặp lại qua các hàng trong DataFrame. Xem câu trả lời này để thay thế.

Nếu bạn vẫn cần lặp lại qua các hàng, bạn có thể sử dụng các phương thức bên dưới. Lưu ý một số cảnh báo quan trọng không được đề cập trong bất kỳ câu trả lời nào khác.

itertuples() được cho là nhanh hơn iterrows()

Nhưng hãy lưu ý, theo các tài liệu (gấu trúc 0.24.2 tại thời điểm này):

  • iterrows: dtypecó thể không khớp từ hàng này sang hàng khác

    Bởi vì các vòng lặp trả về một Chuỗi cho mỗi hàng, nó không bảo toàn các kiểu chữ trên các hàng (các kiểu chữ được bảo toàn trên các cột cho DataFrames). Để bảo toàn các kiểu chữ trong khi lặp qua các hàng, tốt hơn là sử dụng itertuples () trả về các tên được đặt tên của các giá trị và thường nhanh hơn nhiều so với iterrows ()

  • iterrows: Không sửa đổi hàng

    Bạn không bao giờ nên sửa đổi một cái gì đó bạn đang lặp đi lặp lại. Điều này không được đảm bảo để làm việc trong mọi trường hợp. Tùy thuộc vào các loại dữ liệu, iterator trả về một bản sao chứ không phải dạng xem và việc ghi vào nó sẽ không có hiệu lực.

    Sử dụng DataFrame.apply () thay thế:

    new_df = df.apply(lambda x: x * 2)
  • lặp đi lặp lại:

    Tên cột sẽ được đổi tên thành tên vị trí nếu chúng là định danh Python không hợp lệ, được lặp lại hoặc bắt đầu bằng dấu gạch dưới. Với số lượng cột lớn (> 255), các bộ dữ liệu thông thường được trả về.

Xem tài liệu về gấu trúc trên vòng lặp để biết thêm chi tiết.


4
Chỉ là một câu hỏi nhỏ từ một người đọc chủ đề này rất lâu sau khi hoàn thành: làm thế nào df.apply () so sánh với itertuples về hiệu quả?
Raul Guarini

4
Lưu ý: bạn cũng có thể nói điều gì đó giống như for row in df[['c1','c2']].itertuples(index=True, name=None):chỉ bao gồm các cột nhất định trong trình lặp hàng.
Brian đốt cháy

12
Thay vì getattr(row, "c1"), bạn có thể sử dụng chỉ row.c1.
viraptor

1
Tôi chắc chắn khoảng 90% rằng nếu bạn sử dụng getattr(row, "c1")thay vì row.c1, bạn sẽ mất bất kỳ lợi thế về hiệu suất nào itertuplesvà nếu bạn thực sự cần đến tài sản thông qua một chuỗi, thay vào đó bạn nên sử dụng iterrows.
Noctiphobia

3
Tôi đã vấp phải câu hỏi này bởi vì, mặc dù tôi biết có sự kết hợp chia tách, tôi vẫn thực sự cần phải lặp lại trên DataFrame (như câu hỏi nêu). Không phải ai cũng có sự sang trọng để cải thiện numbacython(các tài liệu tương tự nói rằng "Luôn luôn đáng để tối ưu hóa trong Python trước"). Tôi đã viết câu trả lời này để giúp người khác tránh các vấn đề (đôi khi gây nản lòng) vì không có câu trả lời nào khác đề cập đến những lời cảnh báo này. Đánh lừa bất cứ ai hoặc nói "đó là điều đúng đắn" không bao giờ là ý định của tôi. Tôi đã cải thiện câu trả lời.
viddik13

201

Bạn nên sử dụng df.iterrows(). Mặc dù lặp đi lặp lại từng hàng không đặc biệt hiệu quả do Seriescác đối tượng phải được tạo.


12
Đây có phải là nhanh hơn so với chuyển đổi DataFrame thành một mảng numpy (thông qua .values) và hoạt động trực tiếp trên mảng? Tôi có cùng một vấn đề, nhưng cuối cùng đã chuyển đổi sang một mảng numpy và sau đó sử dụng cython.
vgoklani

12
@vgoklani Nếu lặp đi lặp lại từng hàng không hiệu quả và bạn có một mảng numpy không đối tượng thì gần như chắc chắn sử dụng mảng numpy thô sẽ nhanh hơn, đặc biệt là đối với các mảng có nhiều hàng. bạn nên tránh lặp lại qua các hàng trừ khi bạn thực sự phải
Phillip Cloud

7
Tôi đã thực hiện một chút thử nghiệm về mức tiêu thụ thời gian cho df.iterrows (), df.itertuples () và zip (df ['a'], df ['b']) và đăng kết quả trong câu trả lời của người khác câu hỏi: stackoverflow.com/a 432311080/2142098
Richard Wong

154

Trong khi iterrows()là một lựa chọn tốt, đôi khi itertuples()có thể nhanh hơn nhiều:

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

5
Phần lớn sự khác biệt về thời gian trong hai ví dụ của bạn có vẻ như là do thực tế là bạn dường như đang sử dụng lập chỉ mục dựa trên nhãn cho lệnh .iterrows () và lập chỉ mục dựa trên số nguyên cho lệnh .itertuples ().
Alex

2
Đối với khung dữ liệu dựa trên dữ liệu tài chính (dấu thời gian và dấu phẩy 4x), itertuples nhanh hơn 19,57 lần sau đó lặp lại trên máy của tôi. Chỉ for a,b,c in izip(df["a"],df["b"],df["c"]:là gần như nhanh như nhau.
harbun

7
Bạn có thể giải thích tại sao nó nhanh hơn?
Abe Miessler

4
@AbeMiessler đóng iterrows()hộp từng hàng dữ liệu vào Sê-ri, trong khi itertuples()không.
miradulo

3
Lưu ý rằng thứ tự của các cột thực sự không xác định, vì dfđược tạo từ từ điển, do đó row[1]có thể tham chiếu đến bất kỳ cột nào. Khi nó bật ra mặc dù thời gian gần như giống nhau cho số nguyên so với các cột float.
Brian Burns

88

Bạn cũng có thể sử dụng df.apply()để lặp qua các hàng và truy cập nhiều cột cho một hàm.

tài liệu: 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)

Là df ['price'] đề cập đến một tên cột trong khung dữ liệu? Tôi đang cố gắng tạo một từ điển với các giá trị duy nhất từ ​​một số cột trong tệp csv. Tôi đã sử dụng logic của bạn để tạo một từ điển với các khóa và giá trị duy nhất và gặp lỗi khi nêu các đối tượng TypeError: ("'Series' có thể thay đổi, do đó chúng không thể được băm", u'occaded at index 0 ')
SRS

Mã: df ['Workgroup'] = df.apply (lambda row: dic_update (row), angle = 1) end of line id = 0 end of line def dic_update (row): if row not in dic: dic [row] = id id = id + 1
SRS

Không sao, tôi hiểu rồi. Đã thay đổi dòng gọi hàm thành df_new = df ['Workgroup']. Áp dụng (điều tương tự)
SRS

2
Có trục mặc định là 0 là tồi tệ nhất
zthomas.nc

9
Lưu ý rằng applykhông "iteratite" trên các hàng, thay vào đó, nó áp dụng một hàng theo chức năng. Đoạn mã trên sẽ không làm việc nếu bạn thực sự làm lặp đi lặp lại nhu cầu và indeces, ví dụ khi so sánh giá trị trên các hàng khác nhau (trong trường hợp đó bạn có thể làm gì ngoài việc lặp lại).
gạc

82

Bạn có thể sử dụng hàm df.iloc như sau:

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

1
Tôi biết rằng người ta nên tránh điều này để ủng hộ iterrow hoặc itertuples, nhưng sẽ rất thú vị khi biết lý do tại sao. Có suy nghĩ gì không?
rocarvaj

12
Đây là kỹ thuật hợp lệ duy nhất tôi biết nếu bạn muốn bảo tồn các kiểu dữ liệu và cũng tham khảo các cột theo tên. itertuplesbảo tồn các loại dữ liệu, nhưng loại bỏ bất kỳ tên nào nó không thích. iterrowslàm ngược lại.
Ken Williams

6
Đã dành hàng giờ cố gắng lội qua các đặc điểm riêng của cấu trúc dữ liệu gấu trúc để làm một cái gì đó đơn giản VÀ biểu cảm. Điều này dẫn đến mã có thể đọc được.
Sean Anderson

Mặc dù for i in range(df.shape[0])có thể tăng tốc độ tiếp cận này lên một chút, nhưng nó vẫn chậm hơn khoảng 3,5 lần so với cách tiếp cận iterrows () ở trên cho ứng dụng của tôi.
Kim Miller

Trên Datafrmes lớn, điều này có vẻ tốt hơn khi my_iter = df.itertuples()mất gấp đôi bộ nhớ và rất nhiều thời gian để sao chép nó. tương tự cho iterrows().
Bastiaan

33

Tôi đang tìm kiếm Cách lặp trên các hàng VÀ cột và kết thúc ở đây như vậy:

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

18

Bạn có thể viết iterator của riêng bạn mà thực hiện 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)

Điều này là trực tiếp so sánh với pd.DataFrame.itertuples. Tôi đang nhắm đến việc thực hiện cùng một nhiệm vụ với hiệu quả cao hơn.


Đối với khung dữ liệu đã cho với chức năng của tôi:

list(myiter(df))

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

Hoặc với pd.DataFrame.itertuples:

list(df.itertuples(index=False))

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

Một thử nghiệm toàn diện
Chúng tôi kiểm tra làm cho tất cả các cột có sẵn và đặt lại các cột.

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);

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


2
Đối với những người không muốn đọc mã: dòng màu xanh là intertuples, dòng màu cam là danh sách của một trình vòng lặp thông qua khối sản lượng. interrowskhông được so sánh.
James L.

18

Làm thế nào để lặp lại hiệu quả?

Nếu bạn thực sự phải lặp lại một khung dữ liệu gấu trúc, có lẽ bạn sẽ muốn tránh sử dụng iterrows () . Có nhiều phương pháp khác nhau và thông thường iterrows()không phải là tốt nhất. itertuples () có thể nhanh hơn 100 lần.

Nói ngắn gọn:

  • Như một quy tắc chung, sử dụng df.itertuples(name=None). Đặc biệt, khi bạn có một cột số cố định và ít hơn 255 cột. Xem điểm (3)
  • Mặt khác, sử dụng df.itertuples()trừ khi các cột của bạn có các ký tự đặc biệt như dấu cách hoặc '-'. Xem điểm (2)
  • Có thể sử dụng itertuples()ngay cả khi khung dữ liệu của bạn có các cột lạ bằng cách sử dụng ví dụ cuối cùng. Xem điểm (4)
  • Chỉ sử dụng iterrows()nếu bạn không thể các giải pháp trước đó. Xem điểm (1)

Các phương thức khác nhau để lặp lại qua các hàng trong khung dữ liệu gấu trúc:

Tạo một khung dữ liệu ngẫu nhiên với một triệu hàng và 4 cột:

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

1) Thông thường iterrows()là thuận tiện nhưng chậm chết tiệt:

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) Mặc định itertuples()đã nhanh hơn nhiều nhưng nó không hoạt động với các tên cột như My Col-Name is very Strange(bạn nên tránh phương thức này nếu các cột của bạn được lặp lại hoặc nếu một tên cột không thể được chuyển đổi đơn giản thành tên biến python):

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) Mặc định itertuples()sử dụng name = none thậm chí còn nhanh hơn nhưng không thực sự tiện lợi vì bạn phải xác định một biến trên mỗi cột.

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("3. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

4) Cuối cùng, tên itertuples()được đặt chậm hơn điểm trước nhưng bạn không phải xác định biến trên mỗi cột và nó hoạt động với các tên cột như 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("4. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))

Đầu ra:

         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. Itertuples done in 0.94 seconds, result = 66151519
4. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519

Bài viết này là một so sánh rất thú vị giữa iterrow và itertuples


14

Để lặp tất cả các hàng trong một dataframebạn có thể sử dụng:

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

1
Đây là chuỗi chỉ mục. Tôi không khuyên bạn nên làm điều này.
cs95

@ cs95 Bạn muốn giới thiệu gì?
CONvid19

Nếu bạn muốn thực hiện công việc này, hãy gọi df.columns.get_loc để lấy vị trí chỉ số nguyên của cột ngày (bên ngoài vòng lặp), sau đó sử dụng một lệnh gọi lập chỉ mục iloc bên trong.
cs95

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

1
hiệu suất của tùy chọn này như thế nào khi được sử dụng trên một khung dữ liệu lớn (ví dụ hàng triệu hàng)?
Bazyli Debowski

Thành thật mà nói, tôi không biết chính xác, tôi nghĩ rằng so với câu trả lời hay nhất, thời gian trôi qua sẽ giống nhau, bởi vì cả hai trường hợp đều sử dụng "cho" -Xây dựng. Nhưng bộ nhớ có thể khác nhau trong một số trường hợp.
Grag2015

4
Đây là chuỗi chỉ mục. Đừng dùng cái này!
cs95

7

Đôi khi một mẫu hữu ích là:

# 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)

Kết quả nào trong:

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

6

Để lặp tất cả các hàng trong a dataframesử dụng các giá trị của mỗi hàng một cách thuận tiện , namedtuplescó thể được chuyển đổi thành ndarrays. Ví dụ:

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

Lặp lại qua các hàng:

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

kết quả trong:

[ 1.   0.1]
[ 2.   0.2]

Xin lưu ý rằng nếu index=True, chỉ mục được thêm vào như là thành phần đầu tiên của bộ dữ liệu , điều này có thể không mong muốn đối với một số ứng dụng.


5

Có một cách để lặp lại các hàng ném trong khi lấy lại DataFrame và không phải là Sê-ri. Tôi không thấy ai đề cập rằng bạn có thể chuyển chỉ mục dưới dạng danh sách cho hàng được trả về dưới dạng DataFrame:

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

Lưu ý việc sử dụng dấu ngoặc kép. Điều này trả về một DataFrame với một hàng duy nhất.


Điều này rất hữu ích để có được hàng lớn thứ n trong khung dữ liệu sau khi sắp xếp. Cảm ơn!
Jason Harrison

3

Đối với cả xem và sửa đổi giá trị, tôi sẽ sử dụng iterrows(). Trong một vòng lặp for và bằng cách sử dụng bộ giải nén tuple (xem ví dụ i, row:), tôi sử dụng rowchỉ để xem giá trị và sử dụng ivới locphương thức khi tôi muốn sửa đổi giá trị. Như đã nêu trong các câu trả lời trước, ở đây bạn không nên sửa đổi một cái gì đó bạn đang lặp đi lặp lại.

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

Ở đây, rowtrong vòng lặp là một bản sao của hàng đó, và không phải là một khung nhìn của nó. Do đó, bạn KHÔNG nên viết một cái gì đó như thế row['A'] = 'New_Value', nó sẽ không sửa đổi DataFrame. Tuy nhiên, bạn có thể sử dụng ilocvà chỉ định DataFrame để làm việc.


2

Tôi biết tôi đến trễ bên trả lời, nhưng tôi chỉ muốn thêm vào câu trả lời của @ cs95 ở trên, mà tôi tin rằng đó phải là câu trả lời được chấp nhận. Trong câu trả lời của mình, ông cho thấy rằng vector hóa gấu trúc vượt xa các phương pháp gấu trúc khác để tính toán các công cụ với dataframes.

Tôi muốn thêm rằng nếu trước tiên bạn chuyển đổi khung dữ liệu thành một mảng numpy và sau đó sử dụng vector hóa, nó thậm chí còn nhanh hơn so với vector hóa khung dữ liệu của gấu trúc, (và bao gồm cả thời gian để biến nó trở lại thành chuỗi dataframe).

Nếu bạn thêm các chức năng sau vào mã điểm chuẩn của @ cs95, điều này trở nên khá rõ ràng:

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]

nhập mô tả hình ảnh ở đây


1

Bạn cũng có thể thực hiện numpylập chỉ mục để tăng tốc độ thậm chí còn lớn hơn. Nó không thực sự lặp nhưng hoạt động tốt hơn nhiều so với lặp cho một số ứng dụng nhất định.

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

Bạn cũng có thể muốn đúc nó thành một mảng. Các chỉ mục / lựa chọn này được cho là hoạt động giống như các mảng Numpy nhưng tôi gặp vấn đề và cần phải truyền

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

1

Có rất nhiều cách để lặp lại qua các hàng trong khung dữ liệu gấu trúc. Một cách rất đơn giản và trực quan là:

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]])

0

Ví dụ này sử dụng iloc để cô lập từng chữ số trong khung dữ liệu.

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])

0

Một số thư viện (ví dụ: thư viện interop Java mà tôi sử dụng) yêu cầu các giá trị được truyền liên tiếp tại một thời điểm, ví dụ, nếu truyền dữ liệu. Để tái tạo bản chất phát trực tuyến, tôi 'truyền' các giá trị khung dữ liệu của mình từng cái một, tôi đã viết bên dưới, đôi khi nó rất hữu ích.

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

Mà có thể được sử dụng:

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

Và duy trì ánh xạ giá trị / tên cho các hàng được lặp lại. Rõ ràng, chậm hơn rất nhiều so với việc sử dụng áp dụng và Cython như được chỉ ra ở trên, nhưng là cần thiết trong một số trường hợp.


0

Nói ngắn gọn

  • Sử dụng vector hóa nếu có thể
  • Nếu hoạt động không thể được vector hóa - sử dụng danh sách hiểu
  • Nếu bạn cần một đối tượng đại diện cho toàn bộ hàng - hãy sử dụng itertuples
  • Nếu cách trên quá chậm - hãy thử swifter.apply
  • Nếu vẫn còn quá chậm - hãy thử thói quen Cython

Chi tiết trong video này

Điểm chuẩn Điểm chuẩn của lần lặp qua các hàng trong DataFrame của gấu trúc

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.