จะวนซ้ำแถวใน DataFrame ใน Pandas ได้อย่างไร?


1948

ฉันมี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']

เป็นไปได้ไหมที่จะทำเช่นนั้นในแพนด้า

ฉันพบคำถามที่คล้ายกันนี้ แต่มันไม่ได้ให้คำตอบที่ฉันต้องการ ตัวอย่างเช่นแนะนำให้ใช้:

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

หรือ

for row in df.iterrows():

แต่ฉันไม่เข้าใจว่าrowวัตถุคืออะไรและฉันจะทำงานกับมันได้อย่างไร


11
df.iteritems () วนซ้ำคอลัมน์และไม่ใช่แถว ดังนั้นในการทำให้มันวนซ้ำไปตามแถวคุณต้องเปลี่ยน ("T") ซึ่งหมายความว่าคุณเปลี่ยนแถวและคอลัมน์เป็นกันและกัน (สะท้อนกลับในแนวทแยงมุม) เป็นผลให้คุณวนซ้ำ dataframe เดิมได้อย่างมีประสิทธิภาพเมื่อคุณใช้ df.T.iteritems ()
Stefan Gruenwald

11
หากคุณยังใหม่กับกระทู้นี้และเป็นผู้เริ่มต้นในการแพนด้าอย่าทำซ้ำ !! การวนซ้ำบนดาต้าเฟรมเป็นรูปแบบการต่อต้านและสิ่งที่คุณไม่ควรทำถ้าคุณไม่คุ้นเคยกับการรอคอยมากมาย ขึ้นอยู่กับสิ่งที่คุณพยายามจะทำมีทางเลือกที่ดีกว่ามาก iter*ควรใช้ฟังก์ชั่นในสถานการณ์ที่หายากมาก ที่เกี่ยวข้องอีกด้วย
cs95

18
ตรงกันข้ามกับสิ่งที่ cs95 พูดว่ามีเหตุผลที่สมบูรณ์แบบที่จะต้องการย้ำกับดาต้าเฟรมดังนั้นผู้ใช้ใหม่ไม่ควรรู้สึกท้อแท้ ตัวอย่างหนึ่งคือถ้าคุณต้องการรันโค้ดบางอย่างโดยใช้ค่าของแต่ละแถวเป็นอินพุต นอกจากนี้หากไฟล์ข้อมูลของคุณมีขนาดเล็กพอสมควร (เช่นน้อยกว่า 1,000 รายการ) ประสิทธิภาพจะไม่เป็นปัญหา
oulenz

1
@ Louenz: หากมีเหตุผลแปลก ๆ ที่คุณต้องการใช้หน้า API เพื่อจุดประสงค์มันถูกออกแบบมาสำหรับ (การแปลงข้อมูลประสิทธิภาพสูง) แล้วเป็นแขกของฉัน แต่อย่างน้อยที่สุดอย่าใช้iterrowsมันมีวิธีที่ดีกว่าในการวนซ้ำ DataFrame คุณอาจแค่วนซ้ำรายการรายการที่จุดนั้น หากคุณอยู่ในจุดที่คุณไม่ได้ทำอะไรเลย แต่ทำซ้ำผ่าน DataFrames คุณจะไม่ได้รับประโยชน์จากการใช้ DataFrame เลย (การวนซ้ำมันเป็นสิ่งเดียวที่คุณทำ) แค่ 2c ของฉัน
cs95

7
ฉันสอง @oulenz เท่าที่ฉันสามารถบอกได้pandasก็คือตัวเลือกการอ่านไฟล์ csv แม้ว่าชุดข้อมูลจะมีขนาดเล็กก็ตาม การวางโปรแกรมทำได้ง่ายขึ้นเพื่อจัดการข้อมูลด้วย API
Chris

คำตอบ:


2632

DataFrame.iterrowsเป็นตัวสร้างที่ให้ทั้งดัชนีและแถว

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
หมายเหตุ: "เนื่องจาก iterrows ส่งคืนชุดสำหรับแต่ละแถวจึงไม่เก็บ dtypes ข้ามแถว" นอกจากนี้ "คุณไม่ควรแก้ไขสิ่งที่คุณทำซ้ำ" อ้างอิงจากpandas 0.19.1 docs
viddik13

3
@ viddik13 ขอบคุณมากครับ เพราะการที่ฉันวิ่งเข้าไปในกรณีที่ค่าตัวเลขเช่นที่อ่านเป็น431341610650 4.31E+11มีวิธีการรักษา dtypes หรือไม่?
Aziz Alto

26
@ AzizAlto ใช้itertuplesตามที่อธิบายไว้ด้านล่าง ดูเพิ่มเติมที่pandas.pydata.org/pandas-docs/stable/generated/ …
Axel

101
อย่าใช้ iterrows Itertuples เร็วขึ้นและเก็บรักษาชนิดข้อมูลไว้ ข้อมูลเพิ่มเติม
James L.

11
จากเอกสาร : "การวนซ้ำผ่านวัตถุแพนด้ามักจะช้าในหลาย ๆ กรณีไม่จำเป็นต้องวนซ้ำด้วยตนเองในแถว [... ]" คำตอบของคุณถูกต้อง (ในบริบทของคำถาม) แต่ไม่ได้พูดถึงเรื่องนี้ทุกที่ดังนั้นจึงไม่ใช่คำตอบที่ดีมาก
cs95

458

จะวนซ้ำแถวใน DataFrame ใน Pandas ได้อย่างไร?

คำตอบ: ไม่* !

การวนซ้ำในนุ่นเป็นรูปแบบต่อต้านและเป็นสิ่งที่คุณควรทำก็ต่อเมื่อคุณมีทางเลือกอื่นหมดแล้ว คุณไม่ควรใช้ฟังก์ชั่นใด ๆ กับ " iter" ในชื่อของมันมานานกว่าไม่กี่พันแถวหรือคุณจะต้องรับใช้จำนวนมากของการรอคอย

คุณต้องการพิมพ์ DataFrame หรือไม่? DataFrame.to_string()ใช้

คุณต้องการคำนวณบางอย่างหรือไม่? ในกรณีนั้นค้นหาวิธีการตามลำดับนี้ (รายการที่แก้ไขจากที่นี่ ):

  1. vectorization
  2. กิจวัตร Cython
  3. รายการความเข้าใจ ( forวนวานิลลา)
  4. DataFrame.apply(): i) การลดลงที่สามารถทำได้ใน cython, ii) การวนซ้ำในช่องว่างของ python
  5. DataFrame.itertuples() และ iteritems()
  6. DataFrame.iterrows()

iterrowsและitertuples(ทั้งสองได้รับคะแนนเสียงจำนวนมากในการตอบคำถามนี้) ควรใช้ในสถานการณ์ที่หายากมากเช่นการสร้างออบเจ็กต์แถว / nametuples สำหรับการประมวลผลตามลำดับซึ่งเป็นสิ่งเดียวที่ฟังก์ชั่นเหล่านี้มีประโยชน์

อุทธรณ์ไปยังผู้มีอำนาจ
หน้าเอกสารในการทำซ้ำมีช่องเตือนสีแดงขนาดใหญ่ที่ระบุว่า:

การวนซ้ำผ่านวัตถุแพนด้านั้นโดยทั่วไปจะช้า ในหลายกรณีไม่จำเป็นต้องทำการวนซ้ำด้วยตนเองในแถว [... ]

* จริงๆแล้วมันซับซ้อนกว่า "ไม่" เล็กน้อย df.iterrows()เป็นคำตอบที่ถูกต้องสำหรับคำถามนี้ แต่ "vectorize your ops" เป็นคำตอบที่ดีกว่า ฉันจะยอมรับว่ามีสถานการณ์ที่ไม่สามารถหลีกเลี่ยงการวนซ้ำ (ตัวอย่างเช่นการดำเนินการบางอย่างที่ผลลัพธ์ขึ้นอยู่กับค่าที่คำนวณสำหรับแถวก่อนหน้า) อย่างไรก็ตามต้องใช้ความคุ้นเคยกับห้องสมุดในการรู้ว่าเมื่อใด หากคุณไม่แน่ใจว่าคุณต้องการโซลูชันแบบวนซ้ำหรือไม่คุณอาจไม่ต้องการ PS: หากต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับเหตุผลของฉันสำหรับการเขียนคำตอบนี้ให้ข้ามไปที่ด้านล่างสุด


เร็วกว่าวนลูป: Vectorization , Cython

จำนวนของการดำเนินการพื้นฐานและการคำนวณที่ดีคือ "vectorised" โดย pandas (ผ่าน NumPy หรือผ่านฟังก์ชัน Cythonized) ซึ่งรวมถึงเลขคณิตการเปรียบเทียบการลด (ส่วนใหญ่) การปรับรูปร่าง (เช่นการหมุน) การรวมและการดำเนินการของกลุ่ม ดูเอกสารเกี่ยวกับฟังก์ชันการทำงานพื้นฐานที่จำเป็นเพื่อค้นหาวิธีการเวกเตอร์ที่เหมาะสมสำหรับปัญหาของคุณ

ถ้าไม่มีอยู่แล้วรู้สึกฟรีเพื่อเขียนเองโดยใช้กำหนดเองของคุณส่วนขยาย Cython


สิ่งที่ดีที่สุดถัดไป: รายการความเข้าใจ*

รายการความเข้าใจควรเป็นพอร์ตการโทรถัดไปของคุณหาก 1) ไม่มีโซลูชันแบบเวกเตอร์ที่ใช้ได้ 2) ประสิทธิภาพเป็นสิ่งสำคัญ แต่ไม่สำคัญพอที่จะผ่านการยุ่งยากในการ cythonizing รหัสของคุณและ 3) คุณกำลังพยายามทำการแปลงองค์ประกอบ ในรหัสของคุณ มีหลักฐานจำนวนพอสมควรที่จะชี้ให้เห็นว่ารายการความเข้าใจนั้นเร็วพอ (และบางครั้งก็เร็วกว่า) สำหรับงานแพนด้าทั่วไปจำนวนมาก

สูตรง่าย

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

หากคุณสามารถห่อหุ้มตรรกะทางธุรกิจของคุณลงในฟังก์ชั่นคุณสามารถใช้รายการความเข้าใจที่เรียกมัน คุณสามารถทำให้สิ่งที่ซับซ้อนโดยพลการทำงานผ่านความเรียบง่ายและความเร็วของงูเหลือมดิบ


ความเข้าใจในรายการCaveatsถือว่าข้อมูลของคุณนั้นใช้งานได้ง่าย - หมายความว่าประเภทข้อมูลของคุณมีความสอดคล้องกันและคุณไม่มี NaNs แต่สิ่งนี้ไม่สามารถรับประกันได้เสมอไป

  1. วิธีแรกมีความชัดเจนมากขึ้น แต่เมื่อต้องรับมือกับ NaNs ให้เลือกใช้วิธีการทำแพนด้าในตัว (เพราะมีตรรกะการจัดการมุมที่ดีกว่า) หรือตรวจสอบให้แน่ใจว่าตรรกะทางธุรกิจของคุณมีตรรกะการจัดการ NaN ที่เหมาะสม
  2. เมื่อจัดการกับชนิดข้อมูลแบบผสมคุณควรวนซ้ำzip(df['A'], df['B'], ...)แทนที่จะdf[['A', 'B']].to_numpy()เป็นข้อมูลหลังโดยปริยาย upcasts ข้อมูลเป็นชนิดที่พบบ่อยที่สุด ตัวอย่างเช่นถ้า A เป็นตัวเลขและ B คือสตริงto_numpy()จะใช้อาร์เรย์ทั้งหมดเป็นสตริงซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ โชคดีที่zipping คอลัมน์ของคุณเข้าด้วยกันเป็นวิธีแก้ปัญหาที่ตรงไปตรงมาที่สุดสำหรับเรื่องนี้

* YMMV สำหรับเหตุผลที่ระบุไว้ในส่วนCaveatsด้านบน


ตัวอย่างที่ชัดเจน

A + Bขอแสดงให้เห็นถึงความแตกต่างกับตัวอย่างง่ายๆของการเพิ่มสองคอลัมน์หมีแพนด้า นี่คือโอเปอเรเตอร์แบบเวกเตอร์เพื่อให้ง่ายต่อการตัดทอนประสิทธิภาพของวิธีการที่กล่าวถึงข้างต้น

ป้อนคำอธิบายรูปภาพที่นี่

รหัสเปรียบเทียบสำหรับการอ้างอิงของคุณ

ฉันควรจะพูดถึงว่ามันไม่ได้ถูกตัดและแห้งเสมอไป บางครั้งคำตอบของ "วิธีที่ดีที่สุดสำหรับการดำเนินการ" คือ "ขึ้นอยู่กับข้อมูลของคุณ" คำแนะนำของฉันคือทดสอบวิธีการต่าง ๆ ในข้อมูลของคุณก่อนที่จะตัดสินใจ


อ่านเพิ่มเติม

* วิธีการของสตริง Pandas คือ "vectorized" ในแง่ที่ว่ามันถูกระบุไว้ในซีรีย์ แต่ทำงานกับแต่ละองค์ประกอบ กลไกพื้นฐานยังคงวนซ้ำเพราะการดำเนินการกับสตริงนั้นยากที่จะทำให้เป็นเวกเตอร์ได้


ทำไมฉันถึงเขียนคำตอบนี้

แนวโน้มทั่วไปที่ฉันสังเกตเห็นจากผู้ใช้ใหม่คือการถามคำถามของแบบฟอร์ม "ฉันจะทำซ้ำคำสั่ง df เพื่อทำ X ได้อย่างไร" แสดงรหัสที่โทรมาiterrows()ขณะทำอะไรบางอย่างในลูป for นี่คือเหตุผล ผู้ใช้ใหม่ในไลบรารีที่ไม่ได้รับการแนะนำให้รู้จักกับแนวคิดของ vectorization น่าจะมองเห็นรหัสที่แก้ปัญหาของพวกเขาในขณะที่วนซ้ำข้อมูลของพวกเขาเพื่อทำอะไรบางอย่าง ไม่รู้ว่าจะวนซ้ำ DataFrame ได้อย่างไรสิ่งแรกที่พวกเขาทำคือ Google มันและจบลงที่นี่ตามคำถามนี้ จากนั้นพวกเขาเห็นคำตอบที่ยอมรับแล้วบอกพวกเขาถึงวิธีการและพวกเขาปิดตาและเรียกใช้รหัสนี้โดยไม่ต้องตั้งคำถามก่อนหากการทำซ้ำไม่ใช่สิ่งที่ถูกต้อง

จุดประสงค์ของคำตอบนี้คือการช่วยให้ผู้ใช้ใหม่เข้าใจว่าการวนซ้ำไม่จำเป็นต้องเป็นทางออกสำหรับทุกปัญหาและการแก้ปัญหาสำนวนที่ดีกว่าเร็วกว่าและมีอยู่มากขึ้นและคุ้มค่ากับการลงทุนในการสำรวจพวกเขา ฉันไม่ได้พยายามที่จะเริ่มสงครามของการทำซ้ำ vs vectorization แต่ฉันต้องการให้ผู้ใช้ใหม่ได้รับแจ้งเมื่อมีการพัฒนาวิธีแก้ปัญหาของพวกเขาด้วยห้องสมุดนี้


24
นี่เป็นคำตอบเดียวที่เน้นเทคนิคเกี่ยวกับสำนวนที่ควรใช้กับแพนด้าทำให้เป็นคำตอบที่ดีที่สุดสำหรับคำถามนี้ เรียนรู้ที่จะได้รับสิทธิ คำตอบด้วย ขวา รหัส (แทนขวา คำตอบกับ ผิด รหัส - คือไม่มีประสิทธิภาพไม่ได้ขนาดเกินไปพอดีกับข้อมูลที่เฉพาะเจาะจง) เป็นส่วนใหญ่ของหมีแพนด้า (และข้อมูลทั่วไป) การเรียนรู้
LinkBerest

3
ฉันคิดว่าคุณไม่ยุติธรรมต่อการวนรอบแม้ว่าจะเห็นว่ามันช้ากว่าการทดสอบความเข้าใจในรายการของฉันเล็กน้อย เคล็ดลับคือการห่วงแทนzip(df['A'], df['B']) df.iterrows()
คืน

2
@ImperishableNight ไม่เลย; จุดของโพสต์นี้ไม่ได้เป็นการบอกเลิกการทำซ้ำโดยทั่วไป - เป็นการบอกเลิกการใช้งานโดยเฉพาะiterrows()และบอกเลิกการทำซ้ำโดยปริยายหากและเมื่อมีทางเลือกที่ดีกว่า forลูปของตัวเองนั้นโอเค แต่ความเข้าใจในรายการดีกว่าถ้าคุณทำการแปลงองค์ประกอบที่ชาญฉลาด
cs95

1
@sdbbs มีให้ใช้ sort_values ​​เพื่อจัดเรียงข้อมูลของคุณจากนั้นเรียก to_string () กับผลลัพธ์
cs95

1
ภายใต้ความเข้าใจในรายการตัวอย่าง "การวนซ้ำข้ามหลายคอลัมน์" จำเป็นต้องมีข้อแม้: DataFrame.valuesจะแปลงทุกคอลัมน์เป็นชนิดข้อมูลทั่วไป DataFrame.to_numpy()ทำเช่นนี้ด้วย โชคดีที่เราสามารถใช้zipกับคอลัมน์จำนวนเท่าใดก็ได้
David Wasserman

397

ก่อนอื่นให้พิจารณาว่าคุณต้องการวนซ้ำแถวต่างๆใน DataFrame หรือไม่ ดูคำตอบนี้สำหรับทางเลือก

หากคุณยังต้องวนซ้ำแถวคุณสามารถใช้วิธีการด้านล่าง สังเกต คำเตือนที่สำคัญซึ่งไม่ได้กล่าวถึงในคำตอบอื่น ๆ

itertuples() ควรจะเร็วกว่า iterrows()

แต่ระวังตามเอกสาร (pandas 0.24.2 ในขณะนี้):

  • iterrows: dtypeอาจไม่ตรงกันจากแถวหนึ่งไปอีกแถว

    เนื่องจาก iterrows ส่งคืนชุดสำหรับแต่ละแถวจึงไม่เก็บ dtypes ข้ามแถว (dtypes ถูกเก็บรักษาไว้ทั่วทั้งคอลัมน์สำหรับ DataFrames) เพื่อรักษา dtypes ในขณะที่วนรอบแถวจะเป็นการดีกว่าถ้าใช้ itertuples () ซึ่งคืนค่าชื่อของค่าและโดยทั่วไปจะเร็วกว่า iterrows ()

  • iterrows: อย่าแก้ไขแถว

    คุณไม่ควรแก้ไขสิ่งที่คุณทำซ้ำ ไม่รับประกันว่าจะสามารถใช้งานได้ในทุกกรณี ตัววนซ้ำส่งคืนสำเนาไม่ใช่มุมมองและการเขียนลงไปจะไม่มีผลกระทบทั้งนี้ขึ้นอยู่กับชนิดข้อมูล

    ใช้DataFrame.apply ()แทน:

    new_df = df.apply(lambda x: x * 2)
  • itertuples:

    ชื่อคอลัมน์จะถูกเปลี่ยนชื่อเป็นชื่อตำแหน่งหากเป็นตัวระบุ Python ที่ไม่ถูกต้องทำซ้ำหรือเริ่มต้นด้วยเครื่องหมายขีดล่าง ด้วยคอลัมน์จำนวนมาก (> 255) จะส่งคืน tuples ปกติ

ดูหมีแพนด้าเอกสารในการทำซ้ำสำหรับรายละเอียดเพิ่มเติม


4
เพียงคำถามเล็ก ๆ จากคนที่อ่านหัวข้อนี้นานหลังจากเสร็จสิ้น: วิธี df.apply () เปรียบเทียบกับ itertuples ในแง่ของประสิทธิภาพได้อย่างไร
Raul Guarini

4
หมายเหตุ: คุณสามารถพูดบางสิ่งบางอย่างเช่นfor row in df[['c1','c2']].itertuples(index=True, name=None):การรวมเฉพาะบางคอลัมน์ในตัวทำซ้ำแถว
Brian Burns

12
แทนที่จะgetattr(row, "c1")ใช้คุณสามารถrow.c1ใช้ได้
viraptor

1
ฉันแน่ใจว่าประมาณ 90% ว่าถ้าคุณใช้getattr(row, "c1")แทนคุณrow.c1จะสูญเสียความได้เปรียบด้านประสิทธิภาพใด ๆitertuplesและถ้าคุณต้องการไปยังสถานที่ให้บริการผ่านสตริงคุณควรใช้โปรแกรม iterrows แทน
Noctiphobia

3
ฉันสะดุดคำถามนี้เพราะถึงแม้ว่าฉันรู้ว่ามีการผสมผสานแบบแยกกันใช้ แต่ฉันก็ยังจำเป็นต้องทำซ้ำกับ DataFrame (ตามที่คำถาม) ไม่ใช่ทุกคนที่มีความหรูหราที่จะปรับปรุงด้วยnumbaและcython(เอกสารเดียวกันบอกว่า "มันคุ้มค่าที่จะเพิ่มประสิทธิภาพใน Python ก่อนเสมอ") ฉันเขียนคำตอบนี้เพื่อช่วยผู้อื่นหลีกเลี่ยงปัญหา (บางครั้งน่าผิดหวัง) เนื่องจากไม่มีคำตอบอื่น ๆ ที่พูดถึงคำเตือนเหล่านี้ การหลอกลวงใครหรือบอกว่า "นั่นคือสิ่งที่ถูกต้องที่จะทำ" ไม่ใช่ความตั้งใจของฉัน ฉันได้ปรับปรุงคำตอบ
viddik13

201

df.iterrows()คุณควรใช้ แม้ว่าการทำซ้ำแบบแถวต่อแถวนั้นไม่ได้มีประสิทธิภาพโดยเฉพาะอย่างยิ่งเนื่องจากSeriesต้องสร้างวัตถุ


12
สิ่งนี้เร็วกว่าการแปลง DataFrame ไปเป็นอาร์เรย์ numpy (ผ่าน. values) และดำเนินการกับอาร์เรย์โดยตรงหรือไม่ ฉันมีปัญหาเดียวกัน แต่จบลงด้วยการแปลงเป็นอาร์เรย์ numpy แล้วใช้ cython
vgoklani

12
@ vgoklani หากการวนซ้ำแบบแถวต่อแถวนั้นไม่มีประสิทธิภาพและคุณมีอาร์เรย์ที่ไม่ใช่วัตถุคุณก็จะใช้อาร์เรย์ดิบที่ไม่ใช่วัตถุได้เร็วขึ้นโดยเฉพาะอย่างยิ่งสำหรับอาร์เรย์ที่มีหลายแถว คุณควรหลีกเลี่ยงการวนซ้ำแถวยกเว้นว่าคุณจะต้องทำอย่างแน่นอน
Phillip Cloud

7
ฉันทำการทดสอบเกี่ยวกับการสิ้นเปลืองเวลาสำหรับ df.iterrows (), df.itertuples (), และ zip (df ['a'], df ['b']) และโพสต์ผลลัพธ์ในคำตอบของคนอื่น คำถาม: stackoverflow.com/a/34311080/2142098
Richard Wong

154

ในขณะที่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

5
ความแตกต่างของเวลาส่วนใหญ่ในสองตัวอย่างของคุณดูเหมือนว่าเกิดจากข้อเท็จจริงที่ว่าคุณดูเหมือนจะใช้การจัดทำดัชนีตามป้ายกำกับสำหรับคำสั่ง .iterrows () และการจัดทำดัชนีตามจำนวนเต็มสำหรับคำสั่ง. itertuples ()
อเล็กซ์

2
สำหรับ dataframe ที่ใช้ข้อมูลทางการเงิน (timestamp และ 4x float) itertuples จะเร็วขึ้น 19,57 เท่าจากนั้นทำซ้ำบนเครื่องของฉัน เพียงfor a,b,c in izip(df["a"],df["b"],df["c"]:อย่างรวดเร็วเกือบเท่ากัน
harbun

7
คุณช่วยอธิบายได้ไหมว่าทำไมมันถึงเร็วกว่า
Abe Miessler

4
@AbeMiessler ทำiterrows()กล่องข้อมูลแต่ละแถวเข้าไปในซีรี่ส์ในขณะที่itertuples()ไม่มี
miradulo

3
โปรดทราบว่าคำสั่งของคอลัมน์นั้นไม่ได้กำหนดจริงเนื่องจากdfถูกสร้างขึ้นจากพจนานุกรมดังนั้นrow[1]อาจอ้างอิงถึงคอลัมน์ใด ๆ มันปรากฎว่าเวลามีค่าเท่ากันสำหรับจำนวนเต็มกับคอลัมน์ลอย
Brian Burns

88

คุณยังสามารถใช้df.apply()เพื่อย้ำแถวและเข้าถึงหลายคอลัมน์สำหรับฟังก์ชั่น

เอกสาร: 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)

df ['price'] หมายถึงชื่อคอลัมน์ใน data data หรือไม่? ฉันพยายามสร้างพจนานุกรมที่มีค่าไม่ซ้ำกันจากหลายคอลัมน์ในไฟล์ csv ฉันใช้ตรรกะของคุณในการสร้างพจนานุกรมด้วยคีย์และค่าที่ไม่ซ้ำกันและได้รับข้อผิดพลาดที่ระบุTypeError: ("วัตถุ 'ชุด' ไม่แน่นอนดังนั้นจึงไม่สามารถแฮชได้" และคุณอยู่ที่ดัชนี 0 ')
SRS

รหัส: df ['Workclass'] = df.apply (แถวแลมบ์ดา: dic_update (แถว), แกน = 1) จุดสิ้นสุดของ รหัสบรรทัด = 0 สิ้นสุดบรรทัด def dic_update (แถว): ถ้าแถวไม่อยู่ใน dic: dic [แถว] = id id = id + 1
SRS

ไม่เป็นไรฉันเข้าใจแล้ว เปลี่ยนสายเรียกฟังก์ชันเป็นdf_new = df ['Workclass']. ใช้ (สิ่งเดียวกัน)
SRS

2
การมีค่าเริ่มต้นของแกนเป็น 0 เป็นสิ่งที่แย่ที่สุด
zthomas.nc

9
ขอให้สังเกตว่าapplyจะไม่ "iteratite" มากกว่าแถว แต่จะใช้ฟังก์ชั่นแถวที่ชาญฉลาด รหัสข้างต้นจะไม่ทำงานถ้าคุณจริงๆทำซ้ำความต้องการและ indeces ตัวอย่างเช่นเมื่อเปรียบเทียบค่าในแถวที่แตกต่างกัน (ในกรณีที่คุณสามารถทำอะไร แต่วน)
gented

82

คุณสามารถใช้ฟังก์ชัน df.iloc ดังนี้:

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

1
ฉันรู้ว่าควรหลีกเลี่ยงสิ่งนี้ในความโปรดปรานของ iterrows หรือ itertuples แต่มันน่าสนใจที่จะรู้ว่าทำไม ความคิดใด ๆ
rocarvaj

12
นี่เป็นเทคนิคที่ใช้ได้เพียงอย่างเดียวที่ฉันรู้หากคุณต้องการรักษาชนิดข้อมูลและยังอ้างอิงถึงคอลัมน์ตามชื่อ itertuplesเก็บรักษาชนิดข้อมูล แต่กำจัดชื่อใด ๆ ที่ไม่ชอบ iterrowsไม่ตรงข้าม
Ken Williams

6
ใช้เวลาหลายชั่วโมงในการพยายามลุยผ่านโครงสร้างข้อมูลของแพนด้าเพื่อทำสิ่งที่ง่ายและแสดงออก ผลลัพธ์นี้ในรหัสที่อ่านได้
ฌอนแอนเดอ

แม้ว่าfor i in range(df.shape[0])ความเร็วของวิธีนี้จะเพิ่มขึ้นเล็กน้อย แต่ก็ยังช้ากว่าวิธี iterrows () ประมาณ 3.5 เท่าด้านบนสำหรับแอปพลิเคชันของฉัน
Kim Miller

ใน Datafrmes ขนาดใหญ่สิ่งนี้ดูดีกว่าเพราะmy_iter = df.itertuples()ใช้เวลาเป็นสองเท่าของหน่วยความจำและใช้เวลามากในการคัดลอก iterrows()สำหรับเดียวกัน
Bastiaan

33

ฉันกำลังหาวิธีวนซ้ำแถวและคอลัมน์และสิ้นสุดที่นี่ดังนั้น:

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

18

คุณสามารถเขียนตัววนซ้ำของคุณเองที่ดำเนินการ 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ก็เปรียบได้โดยตรงกับ ฉันตั้งเป้าหมายที่จะทำงานที่มีประสิทธิภาพมากกว่าเดิม


สำหรับ dataframe ที่กำหนดด้วยฟังก์ชันของฉัน:

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

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่


2
สำหรับผู้ที่ไม่ต้องการอ่านรหัส: เส้นสีน้ำเงินคือintertuplesเส้นสีส้มคือรายการของตัววนซ้ำถึงบล็อกผลผลิต interrowsไม่ได้เปรียบเทียบ
James L.

18

วิธีการวนซ้ำอย่างมีประสิทธิภาพ?

หากคุณจริงๆต้องย้ำ dataframe นุ่นคุณอาจจะต้องการที่จะหลีกเลี่ยงการใช้ iterrows () มีวิธีการที่แตกต่างกันและวิธีiterrows()การที่ดีที่สุดคือ itertuples () สามารถเร็วขึ้น 100 เท่า

ในระยะสั้น:

  • df.itertuples(name=None)ตามกฎทั่วไปใช้ โดยเฉพาะอย่างยิ่งเมื่อคุณมีคอลัมน์จำนวนคงที่และน้อยกว่า 255 คอลัมน์ เห็นจุด (3)
  • มิฉะนั้นให้ใช้df.itertuples()ยกเว้นว่าคอลัมน์ของคุณมีอักขระพิเศษเช่นช่องว่างหรือ '-' เห็นจุด (2)
  • เป็นไปได้ที่จะใช้itertuples()แม้ว่า dataframe ของคุณจะมีคอลัมน์แปลก ๆ โดยใช้ตัวอย่างสุดท้าย เห็นจุด (4)
  • ใช้เฉพาะiterrows()เมื่อคุณไม่สามารถแก้ไขปัญหาก่อนหน้านี้ เห็นจุด (1)

วิธีต่างๆในการวนซ้ำแถวต่างๆใน dataframe แพนด้า:

สร้างดาต้าเฟรมแบบสุ่มด้วยล้านแถวและ 4 คอลัมน์:

    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()เร็วกว่ามากแล้ว แต่มันไม่ทำงานกับชื่อคอลัมน์เช่นMy Col-Name is very Strange(คุณควรหลีกเลี่ยงวิธีนี้หากคอลัมน์ของคุณซ้ำแล้วซ้ำอีกหรือถ้าชื่อคอลัมน์ไม่สามารถแปลงเป็นชื่อตัวแปรไพ ธ อนได้):

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(_, 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 = 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))

เอาท์พุท:

         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

บทความนี้เป็นการเปรียบเทียบที่น่าสนใจระหว่าง iterrows และ itertuples


14

ในการวนซ้ำแถวทั้งหมดใน a dataframeคุณสามารถใช้:

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

1
นี่คือการจัดทำดัชนีที่ถูกผูกมัด ฉันไม่แนะนำให้ทำเช่นนี้
cs95

@ cs95 คุณจะแนะนำอะไรแทน
CONVID19

หากคุณต้องการใช้งานนี้ให้โทร df.columns.get_loc เพื่อรับตำแหน่งดัชนีจำนวนเต็มของคอลัมน์วันที่ (นอกลูป) จากนั้นใช้การเรียกการจัดทำดัชนี iloc เดียวภายใน
cs95

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

1
ประสิทธิภาพของตัวเลือกนี้เมื่อใช้กับ dataframe ขนาดใหญ่ (ตัวอย่างเช่นมีหลายล้านแถว)?
Bazyli Debowski

จริงๆแล้วฉันไม่รู้เหมือนกันฉันคิดว่าเมื่อเทียบกับคำตอบที่ดีที่สุดเวลาที่ใช้จะเหมือนกันเพราะทั้งสองกรณีใช้ "สำหรับ" - การก่อสร้าง แต่หน่วยความจำอาจแตกต่างกันในบางกรณี
Grag2015

4
นี่คือการจัดทำดัชนีที่ถูกผูกมัด อย่าใช้สิ่งนี้!
cs95

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}

6

ห่วงแถวทั้งหมดใน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, ดัชนีจะถูกเพิ่มเป็นองค์ประกอบแรกของ tupleซึ่งอาจจะเป็นที่ไม่พึงประสงค์สำหรับการใช้งานบางอย่าง


5

มีวิธีการวนแถวในขณะที่รับ DataFrame เป็นการตอบแทนไม่ใช่แบบ ฉันไม่เห็นใครพูดถึงว่าคุณสามารถส่งดัชนีเป็นรายการสำหรับแถวที่จะส่งคืนเป็น DataFrame:

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

สังเกตการใช้งานของวงเล็บคู่ ส่งคืน DataFrame ด้วยแถวเดียว


สิ่งนี้มีประโยชน์มากสำหรับการทำให้แถวที่ใหญ่ที่สุดลำดับที่เก้าในกรอบข้อมูลหลังจากการเรียงลำดับ ขอบคุณ!
Jason Harrison

3

iterrows()สำหรับทั้งการดูและการปรับเปลี่ยนค่าผมจะใช้ ใน a for loop และโดยใช้ tuple unpacking (ดูตัวอย่าง:) i, rowฉันใช้rowเพื่อดูค่าและใช้iกับlocวิธีเมื่อฉันต้องการแก้ไขค่า ตามที่ระบุไว้ในคำตอบก่อนหน้านี้ที่นี่คุณไม่ควรแก้ไขสิ่งที่คุณทำซ้ำ

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 อย่างไรก็ตามคุณสามารถใช้iและlocและระบุ DataFrame ที่จะทำผลงาน


2

ฉันรู้ว่าฉันมางานปาร์ตี้สาย แต่ฉันต้องการเพิ่มคำตอบของ @ cs95 ด้านบนซึ่งฉันเชื่อว่าควรเป็นคำตอบที่ยอมรับได้ ในคำตอบของเขาเขาแสดงให้เห็นว่า vectorization ของ pandas มีประสิทธิภาพเหนือกว่าวิธีอื่นของ pandas สำหรับการคำนวณเนื้อหาด้วย dataframes

ฉันต้องการเพิ่มว่าถ้าคุณแปลงดาต้าเฟรมให้เป็นอาเรมนันซี่แล้วใช้เวกเตอร์ก็จะยิ่งเร็วกว่าเวกเตอร์แพนด้าดาต้าดาต้าไลซ์

หากคุณเพิ่มฟังก์ชั่นต่อไปนี้ในโค้ดมาตรฐานของ @ 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]

ป้อนคำอธิบายรูปภาพที่นี่


1

คุณสามารถnumpyสร้างดัชนีเพื่อเพิ่มความเร็วได้มากขึ้น มันไม่ได้วนซ้ำจริงๆ แต่ทำงานได้ดีกว่าการทำซ้ำสำหรับบางแอปพลิเคชัน

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

คุณอาจต้องการที่จะส่งไปยังอาร์เรย์ ดัชนี / การเลือกเหล่านี้ควรจะทำหน้าที่เหมือน Numpy arrays แล้ว แต่ฉันพบปัญหาและจำเป็นต้องร่าย

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

1

มีหลายวิธีในการวนซ้ำแถวต่างๆใน dataframe แพนด้า วิธีหนึ่งที่ง่ายและใช้งานง่ายคือ:

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

ตัวอย่างนี้ใช้ iloc เพื่อแยกแต่ละหลักใน data data

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

บางไลบรารี (เช่นไลบรารี Java interop ที่ฉันใช้) ต้องการค่าที่จะส่งผ่านในแต่ละครั้งตัวอย่างเช่นหากสตรีมข้อมูล ในการทำซ้ำลักษณะการสตรีมฉัน 'สตรีม' ดาต้าเบสของฉันมีค่าทีละหนึ่งฉันเขียนด้านล่างซึ่งมีประโยชน์เป็นครั้งคราว

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

และรักษาการแม็พค่า / ชื่อสำหรับแถวที่ถูกวนซ้ำ เห็นได้ชัดว่าช้ากว่าการใช้งานมากและ Cython ดังที่ระบุไว้ข้างต้น แต่มีความจำเป็นในบางสถานการณ์


0

ในระยะสั้น

  • ใช้ vectorization ถ้าเป็นไปได้
  • หากการดำเนินการไม่สามารถทำเป็นเวกเตอร์ได้ให้ใช้ความเข้าใจในรายการ
  • หากคุณต้องการวัตถุเดียวที่แสดงแถวทั้งหมด - ใช้ itertuples
  • หากข้างต้นช้าเกินไป - ลอง swifter.apply
  • หากยังช้าเกินไปให้ลองใช้ชุดคำสั่ง Cython

รายละเอียดในวิดีโอนี้

เกณฑ์มาตรฐาน เกณฑ์มาตรฐานของการวนซ้ำแถวต่างๆใน DataFrame แพนด้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.