จะวนซ้ำแถวใน DataFrame ใน Pandas ได้อย่างไร?
คำตอบ: ไม่* !
การวนซ้ำในนุ่นเป็นรูปแบบต่อต้านและเป็นสิ่งที่คุณควรทำก็ต่อเมื่อคุณมีทางเลือกอื่นหมดแล้ว คุณไม่ควรใช้ฟังก์ชั่นใด ๆ กับ " iter
" ในชื่อของมันมานานกว่าไม่กี่พันแถวหรือคุณจะต้องรับใช้จำนวนมากของการรอคอย
คุณต้องการพิมพ์ DataFrame หรือไม่? DataFrame.to_string()
ใช้
คุณต้องการคำนวณบางอย่างหรือไม่? ในกรณีนั้นค้นหาวิธีการตามลำดับนี้ (รายการที่แก้ไขจากที่นี่ ):
- vectorization
- กิจวัตร Cython
- รายการความเข้าใจ (
for
วนวานิลลา)
DataFrame.apply()
: i) การลดลงที่สามารถทำได้ใน cython, ii) การวนซ้ำในช่องว่างของ python
DataFrame.itertuples()
และ iteritems()
DataFrame.iterrows()
iterrows
และitertuples
(ทั้งสองได้รับคะแนนเสียงจำนวนมากในการตอบคำถามนี้) ควรใช้ในสถานการณ์ที่หายากมากเช่นการสร้างออบเจ็กต์แถว / nametuples สำหรับการประมวลผลตามลำดับซึ่งเป็นสิ่งเดียวที่ฟังก์ชั่นเหล่านี้มีประโยชน์
อุทธรณ์ไปยังผู้มีอำนาจ
หน้าเอกสารในการทำซ้ำมีช่องเตือนสีแดงขนาดใหญ่ที่ระบุว่า:
การวนซ้ำผ่านวัตถุแพนด้านั้นโดยทั่วไปจะช้า ในหลายกรณีไม่จำเป็นต้องทำการวนซ้ำด้วยตนเองในแถว [... ]
* จริงๆแล้วมันซับซ้อนกว่า "ไม่" เล็กน้อย df.iterrows()
เป็นคำตอบที่ถูกต้องสำหรับคำถามนี้ แต่ "vectorize your ops" เป็นคำตอบที่ดีกว่า ฉันจะยอมรับว่ามีสถานการณ์ที่ไม่สามารถหลีกเลี่ยงการวนซ้ำ (ตัวอย่างเช่นการดำเนินการบางอย่างที่ผลลัพธ์ขึ้นอยู่กับค่าที่คำนวณสำหรับแถวก่อนหน้า) อย่างไรก็ตามต้องใช้ความคุ้นเคยกับห้องสมุดในการรู้ว่าเมื่อใด หากคุณไม่แน่ใจว่าคุณต้องการโซลูชันแบบวนซ้ำหรือไม่คุณอาจไม่ต้องการ PS: หากต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับเหตุผลของฉันสำหรับการเขียนคำตอบนี้ให้ข้ามไปที่ด้านล่างสุด
จำนวนของการดำเนินการพื้นฐานและการคำนวณที่ดีคือ "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 แต่สิ่งนี้ไม่สามารถรับประกันได้เสมอไป
- วิธีแรกมีความชัดเจนมากขึ้น แต่เมื่อต้องรับมือกับ NaNs ให้เลือกใช้วิธีการทำแพนด้าในตัว (เพราะมีตรรกะการจัดการมุมที่ดีกว่า) หรือตรวจสอบให้แน่ใจว่าตรรกะทางธุรกิจของคุณมีตรรกะการจัดการ NaN ที่เหมาะสม
- เมื่อจัดการกับชนิดข้อมูลแบบผสมคุณควรวนซ้ำ
zip(df['A'], df['B'], ...)
แทนที่จะdf[['A', 'B']].to_numpy()
เป็นข้อมูลหลังโดยปริยาย upcasts ข้อมูลเป็นชนิดที่พบบ่อยที่สุด ตัวอย่างเช่นถ้า A เป็นตัวเลขและ B คือสตริงto_numpy()
จะใช้อาร์เรย์ทั้งหมดเป็นสตริงซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ โชคดีที่zip
ping คอลัมน์ของคุณเข้าด้วยกันเป็นวิธีแก้ปัญหาที่ตรงไปตรงมาที่สุดสำหรับเรื่องนี้
* YMMV สำหรับเหตุผลที่ระบุไว้ในส่วนCaveatsด้านบน
ตัวอย่างที่ชัดเจน
A + B
ขอแสดงให้เห็นถึงความแตกต่างกับตัวอย่างง่ายๆของการเพิ่มสองคอลัมน์หมีแพนด้า นี่คือโอเปอเรเตอร์แบบเวกเตอร์เพื่อให้ง่ายต่อการตัดทอนประสิทธิภาพของวิธีการที่กล่าวถึงข้างต้น
รหัสเปรียบเทียบสำหรับการอ้างอิงของคุณ
ฉันควรจะพูดถึงว่ามันไม่ได้ถูกตัดและแห้งเสมอไป บางครั้งคำตอบของ "วิธีที่ดีที่สุดสำหรับการดำเนินการ" คือ "ขึ้นอยู่กับข้อมูลของคุณ" คำแนะนำของฉันคือทดสอบวิธีการต่าง ๆ ในข้อมูลของคุณก่อนที่จะตัดสินใจ
อ่านเพิ่มเติม
* วิธีการของสตริง Pandas คือ "vectorized" ในแง่ที่ว่ามันถูกระบุไว้ในซีรีย์ แต่ทำงานกับแต่ละองค์ประกอบ กลไกพื้นฐานยังคงวนซ้ำเพราะการดำเนินการกับสตริงนั้นยากที่จะทำให้เป็นเวกเตอร์ได้
ทำไมฉันถึงเขียนคำตอบนี้
แนวโน้มทั่วไปที่ฉันสังเกตเห็นจากผู้ใช้ใหม่คือการถามคำถามของแบบฟอร์ม "ฉันจะทำซ้ำคำสั่ง df เพื่อทำ X ได้อย่างไร" แสดงรหัสที่โทรมาiterrows()
ขณะทำอะไรบางอย่างในลูป for นี่คือเหตุผล ผู้ใช้ใหม่ในไลบรารีที่ไม่ได้รับการแนะนำให้รู้จักกับแนวคิดของ vectorization น่าจะมองเห็นรหัสที่แก้ปัญหาของพวกเขาในขณะที่วนซ้ำข้อมูลของพวกเขาเพื่อทำอะไรบางอย่าง ไม่รู้ว่าจะวนซ้ำ DataFrame ได้อย่างไรสิ่งแรกที่พวกเขาทำคือ Google มันและจบลงที่นี่ตามคำถามนี้ จากนั้นพวกเขาเห็นคำตอบที่ยอมรับแล้วบอกพวกเขาถึงวิธีการและพวกเขาปิดตาและเรียกใช้รหัสนี้โดยไม่ต้องตั้งคำถามก่อนหากการทำซ้ำไม่ใช่สิ่งที่ถูกต้อง
จุดประสงค์ของคำตอบนี้คือการช่วยให้ผู้ใช้ใหม่เข้าใจว่าการวนซ้ำไม่จำเป็นต้องเป็นทางออกสำหรับทุกปัญหาและการแก้ปัญหาสำนวนที่ดีกว่าเร็วกว่าและมีอยู่มากขึ้นและคุ้มค่ากับการลงทุนในการสำรวจพวกเขา ฉันไม่ได้พยายามที่จะเริ่มสงครามของการทำซ้ำ vs vectorization แต่ฉันต้องการให้ผู้ใช้ใหม่ได้รับแจ้งเมื่อมีการพัฒนาวิธีแก้ปัญหาของพวกเขาด้วยห้องสมุดนี้