วิธีที่เหมาะสม™ในการสร้าง DataFrame
TLDR; (เพียงอ่านข้อความที่เป็นตัวหนา)
คำตอบส่วนใหญ่ที่นี่จะบอกคุณถึงวิธีการสร้าง DataFrame ที่ว่างเปล่าและกรอกข้อมูล แต่ไม่มีใครจะบอกคุณว่ามันเป็นสิ่งที่ไม่ดีที่จะทำ
นี่คือคำแนะนำของฉัน: รอจนกว่าคุณจะแน่ใจว่าคุณมีข้อมูลทั้งหมดที่คุณต้องการใช้งาน ใช้รายการเพื่อรวบรวมข้อมูลของคุณจากนั้นเริ่มต้น DataFrame เมื่อคุณพร้อม
data = []
for a, b, c in some_function_that_yields_data():
data.append([a, b, c])
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
มันถูกกว่าเสมอที่จะผนวกเข้ากับรายการและสร้าง DataFrame ในครั้งเดียวมากกว่าที่จะสร้าง DataFrame ที่ว่างเปล่า (หรือหนึ่งใน NaNs) และผนวกกับมันซ้ำแล้วซ้ำอีก รายการยังใช้หน่วยความจำน้อยลงและเป็นโครงสร้างข้อมูลที่เบากว่ามากในการทำงานผนวกและลบ (ถ้าจำเป็น)
ข้อได้เปรียบอื่น ๆ ของวิธีนี้dtypes
จะถูกอนุมานโดยอัตโนมัติ (แทนที่จะกำหนดobject
กับพวกเขาทั้งหมด)
ข้อได้เปรียบสุดท้ายคือa RangeIndex
ถูกสร้างขึ้นโดยอัตโนมัติสำหรับข้อมูลของคุณดังนั้นจึงเป็นสิ่งที่กังวลน้อยกว่า (ดูที่วิธีการที่ไม่ดีappend
และloc
ด้านล่างคุณจะเห็นองค์ประกอบทั้งสองที่จำเป็นต้องจัดการกับดัชนีอย่างเหมาะสม)
สิ่งที่คุณไม่ควรทำ
append
หรือconcat
ภายในวง
นี่คือความผิดพลาดที่ใหญ่ที่สุดที่ฉันเคยเห็นจากผู้เริ่มต้น:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
# or similarly,
# df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)
หน่วยความจำเป็นอีกครั้งที่จัดสรรสำหรับทุกappend
หรือconcat
การดำเนินการที่คุณมี คู่นี้มีห่วงและคุณมีการดำเนินงานที่ซับซ้อนสมการกำลังสอง จากdf.append
หน้าเอกสาร :
การต่อแถวเข้ากับ DataFrame ซ้ำ ๆ อาจทำให้การคำนวณเข้มข้นกว่าการต่อข้อมูลเดียว ทางออกที่ดีกว่าคือการผนวกแถวเหล่านั้นเข้ากับรายการแล้วเชื่อมต่อรายการกับ DataFrame ดั้งเดิมทั้งหมดพร้อมกัน
ข้อผิดพลาดอื่น ๆ ที่เกี่ยวข้องกับdf.append
คือผู้ใช้มักจะลืมผนวกไม่ใช่ฟังก์ชั่นในสถานที่ดังนั้นผลจะต้องได้รับมอบหมายกลับ คุณต้องกังวลเกี่ยวกับโรคไข้เลือดออกด้วย:
df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)
df.dtypes
A object # yuck!
B float64
C object
dtype: object
การจัดการกับคอลัมน์ของวัตถุนั้นไม่ใช่สิ่งที่ดีนักเนื่องจากนุ่นไม่สามารถทำให้การดำเนินการในคอลัมน์เหล่านั้นเป็นเวกเตอร์ได้ คุณจะต้องทำสิ่งนี้เพื่อแก้ไข:
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
loc
ภายในวง
ฉันเคยเห็นเคยloc
ใช้ผนวก DataFrame ที่ถูกสร้างขึ้นที่ว่างเปล่า:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df.loc[len(df)] = [a, b, c]
ก่อนที่คุณยังไม่ได้ก่อนการจัดสรรจำนวนหน่วยความจำที่คุณต้องการในแต่ละครั้งเพื่อให้หน่วยความจำใหม่เติบโตขึ้นทุกครั้งที่คุณสร้างแถวใหม่ มันก็แย่เหมือนกันappend
มากและน่าเกลียดยิ่งกว่าเดิม
DataFrame ว่างเปล่าของ NaNs
จากนั้นมีการสร้าง DataFrame ของ NaN และคำเตือนทั้งหมดที่เกี่ยวข้อง
df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
A B C
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
มันสร้าง DataFrame ของคอลัมน์วัตถุเช่นอื่น ๆ
df.dtypes
A object # you DON'T want this
B object
C object
dtype: object
การผนวกยังคงมีปัญหาทั้งหมดตามวิธีการด้านบน
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
หลักฐานอยู่ในพุดดิ้ง
การกำหนดเวลาวิธีการเหล่านี้เป็นวิธีที่เร็วที่สุดในการดูว่ามีความแตกต่างในแง่ของหน่วยความจำและยูทิลิตี้อย่างไร
รหัสเปรียบเทียบสำหรับการอ้างอิง