set_index ใน pandas ผมใช้สำหรับตั้งคอลัมน์ใดคอลัมน์หนึ่ง (หรือหลายคอลัมน์) ให้กลายเป็น index หลักของ DataFrame เหมือนกับการกำหนดคีย์หลักให้ตาราง เพื่อให้ค้นหาข้อมูลด้วย .loc[] ได้อย่างรวดเร็วและตรงจุดครับ
df.set_index(keys, drop, append)
df.set_index(keys, drop, append)
DataFrame
คืนเป็น DataFrame ใหม่ที่มี index ที่เราตั้งแล้วครับ ต่อ .loc[] ได้ทันที หรือจะเก็บไว้ในตัวแปรใหม่เพื่อใช้งานต่อก็ได้
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| keys | str | list | Yes | ชื่อคอลัมน์ที่ต้องการตั้งเป็น index เช่น ‘product_id’ หรือ [‘year’, ‘month’] สำหรับ MultiIndex | |
| drop | bool | Optional | True | ถ้า True จะลบคอลัมน์ที่กลายเป็น index ออกจากส่วนข้อมูลปกติ (default) ถ้า False จะเก็บคอลัมน์นั้นไว้ด้วย |
| append | bool | Optional | False | ถ้า True จะเพิ่มคอลัมน์ที่เลือกต่อท้าย index เดิมแทนที่จะแทนที่ ใช้ตอนอยากเก็บ index เก่าไว้ด้วย |
df.set_index('product_id').loc['A002']df.set_index('product_id').loc['A002']
name ดินสอ
price 10
Name: A002, dtype: object
df_mi.loc[2023]df_mi.loc[2023]
sales
month
Jan 100
Feb 150
df.set_index('product_id', drop=False)df.set_index('product_id', drop=False)
product_id name price
product_id
A001 A001 ปากกา 25
A002 A002 ดินสอ 10
A003 A003 ยางลบ 5
df_idx.loc['A001', 'price']df_idx.loc['A001', 'price']
25
ไม่ครับ pandas ไม่แก้ DataFrame เดิมของเรา แต่คืน DataFrame ใหม่ที่มี index ใหม่มาให้ ผมเลยต้องเขียน df_new = df.set_index(‘product_id’) หรือถ้าอยากให้แก้ตัวเองเลยก็เพิ่ม inplace=True เข้าไปครับ แต่ผมไม่ค่อยแนะนำ inplace เพราะ debug ยากกว่า
ถ้า index มีค่าซ้ำ .loc[] จะคืนแถวทั้งหมดที่ตรงกันออกมาเป็น DataFrame ครับ ไม่ใช่แถวเดียว เช่น ถ้าสินค้า A001 มีอยู่ 3 แถว df.loc[‘A001’] จะได้ DataFrame 3 แถว ผมเจอบ้างนะครับ ตอนแรกงงว่าทำไมได้หลายแถว สรุปคือ set_index ไม่บังคับว่า index ต้องไม่ซ้ำครับ ต่างจาก primary key ใน database
ได้ผลเหมือนกันครับ แต่วิธีคิดและประสิทธิภาพต่างกัน df[df[‘col’] == value] คือการสแกนทุกแถวเพื่อเปรียบเทียบ ส่วน .loc[] หลัง set_index ใช้ index lookup ซึ่งเร็วกว่ามากเวลาข้อมูลเยอะครับ แถมโค้ดอ่านง่ายกว่าด้วย ผมเลยชอบ set_index + loc กว่าในกรณีที่ต้องค้นหาบ่อยๆ
ปกติเวลาสร้าง DataFrame ใหม่ pandas จะใส่เลข 0, 1, 2, 3 … เป็น index ให้อัตโนมัติ ซึ่งก็ใช้ได้ แต่ถ้าข้อมูลเรามีคอลัมน์ที่ระบุตัวตนของแต่ละแถวอยู่แล้ว เช่น รหัสสินค้า ชื่อพนักงาน หรือวันที่ ผมจะตั้งคอลัมน์นั้นเป็น index แทนเลขลำดับครับ
วิธีคิดง่ายๆ คือนึกถึง Excel ที่เราตรึงคอลัมน์ A ไว้เป็นคีย์อ้างอิง แล้วใช้ VLOOKUP หาค่าจากคีย์นั้น — set_index ทำแบบเดียวกันครับ แต่หลังจาก set_index แล้ว เราใช้ .loc[] แทน VLOOKUP ได้เลย ไม่ต้องระบุหมายเลขแถว
ที่เจ๋งคือเราตั้ง index หลายคอลัมน์พร้อมกันได้เลย (MultiIndex) คล้ายกับการจัดกลุ่มข้อมูลใน PivotTable ที่มี Row Label ซ้อนกันหลายระดับ ทำให้กรองข้อมูลแบบลำดับชั้นได้สวยมากครับ ✨
ส่วนตัวผมชอบใช้ set_index ก่อนจะทำ .loc[] lookup ครับ เพราะพอมี index ที่มีความหมายแล้ว โค้ดอ่านง่ายขึ้นชัดเจนเลย แทนที่จะเขียน df[df[‘product_id’] == ‘A001’] ก็เขียนแค่ df.loc[‘A001’] แทนได้เลย 😎