.loc และ .iloc
ประมาณ 25 นาที
เป้าหมายของบท
- เข้าใจความต่างของ .loc (อ้างอิงด้วย label) กับ .iloc (อ้างอิงด้วยตำแหน่ง)
- เลือกทั้งแถวและคอลัมน์พร้อมกันด้วย .loc/.iloc
- รู้ว่าช่วงท้ายของ .loc รวมด้วย (inclusive) ต่างจาก .iloc/slice ปกติของ Python ที่ไม่รวม (exclusive)
label กับ position
pandas มีสองวิธีหลักในการเลือกแถว/คอลัมน์:
| อ้างอิงด้วย | ตัวอย่าง | |
|---|---|---|
.loc |
label (ชื่อคอลัมน์ / ค่าดัชนี) | df.loc[3] → แถวที่มี index label เป็น 3 |
.iloc |
position (ตำแหน่ง เริ่มจาก 0) | df.iloc[3] → แถวที่ 4 นับจากบน ไม่ว่า label จะเป็นอะไร |
ถ้า DataFrame มี index เป็นตัวเลขเรียงต่อกันตั้งแต่ 0 (ค่าเริ่มต้นหลัง read_csv) .loc[3] กับ .iloc[3]
จะให้ผลเหมือนกัน แต่ถ้า index ถูกเปลี่ยน (เช่นด้วย .set_index() หรือหลังกรอง/เรียงข้อมูล) สองอันนี้จะให้ผลต่างกันทันที
เลือกทั้งแถวและคอลัมน์พร้อมกัน
products.loc[products['category'] == 'Books', ['product_name', 'price']]
products.iloc[0:3, 0:2]
ใส่แกนแถวและแกนคอลัมน์ในวงเล็บเดียวกัน คั่นด้วยจุลภาค — ทำได้ในคำสั่งเดียว ไม่ต้องเขียนกรองแล้วเลือกคอลัมน์แยกกัน
ช่วง (slice): .loc รวมขอบท้าย, .iloc ไม่รวม
df.loc[0:2] # ได้ label 0, 1, 2 (3 แถว — รวมขอบท้าย)
df.iloc[0:2] # ได้ตำแหน่ง 0, 1 (2 แถว — ไม่รวมขอบท้าย เหมือน slice ปกติของ Python)
นี่คือจุดที่มือใหม่มักสับสน: .loc ปฏิบัติต่อช่วงแบบ “รวมทั้งสองขอบ” ในขณะที่ .iloc (และ slice ของ Python
ทั่วไปอย่าง list[0:2]) ปฏิบัติแบบ “ไม่รวมขอบท้าย” จำไว้ว่า .loc เป็นข้อยกเว้น ไม่ใช่กติกาปกติ
ตั้ง index เอง แล้วใช้ .loc อ้างอิงด้วย label ที่มีความหมาย
orders.set_index('order_id').loc[1] # ดึงออเดอร์ที่ order_id = 1 โดยตรง
การตั้งคอลัมน์ที่มีความหมาย (เช่น รหัสที่ไม่ซ้ำ) เป็น index แล้วใช้ .loc อ้างอิงด้วยรหัสนั้นตรงๆ
อ่านง่ายกว่าการกรองด้วยเงื่อนไข df[df['order_id'] == 1] เมื่อรู้ค่าที่ต้องการแน่นอนอยู่แล้ว
ตัวอย่างแก้โจทย์
กด "ขั้นต่อไป" ทีละขั้น ลองรันและแก้โค้ดในแต่ละขั้นได้
ดึงแถวและคอลัมน์ด้วยตำแหน่ง (.iloc)
อยากดึงข้อมูลบางส่วนของตาราง products โดยอ้างอิงด้วย "ตำแหน่ง" ไม่ใช่ชื่อคอลัมน์หรือเงื่อนไข
.iloc[0]ดึงแถวแรก (ตำแหน่ง 0) ทั้งแถว ได้ผลเป็น Series
ดึงข้อมูลด้วยเงื่อนไข พร้อมเลือกคอลัมน์ (.loc)
อยากดูเฉพาะสินค้าหมวด Books และแสดงแค่บางคอลัมน์
.loc[เงื่อนไข]กรองแถวด้วยเงื่อนไข boolean เหมือนdf[เงื่อนไข]ทั่วไป
เติมช่องว่าง
แทน ___ ด้วยโค้ดที่ถูกต้อง แล้วกดตรวจคำตอบ
ดึงเฉพาะลูกค้าจากเมือง Phuket แสดงคอลัมน์ customer_id กับ signup_date เก็บไว้ในตัวแปร result
เติม ___ ให้ครบ
แบบฝึกท้ายบท
บทนี้จะนับว่าเสร็จเมื่อผ่านข้อพื้นฐานและประยุกต์ครบ ข้อท้าทายได้ดาวเพิ่ม
🟢 พื้นฐาน
แถวสุดท้ายของตาราง products (ใช้ .iloc) แสดง product_name กับ price เก็บไว้ในตัวแปร result
ตำแหน่งที่ 5 ถึง 9 (นับจาก 0) ของ customers แสดง customer_id กับ city เก็บไว้ในตัวแปร result
จำนวนลูกค้าที่อยู่เมือง Bangkok (ใช้ .loc) เก็บไว้ในตัวแปร n_bangkok
ต้นทุน (cost) ของสินค้าชิ้นแรกในตาราง (ใช้ .iloc ดึงค่าเดียว จากคอลัมน์สุดท้าย) เก็บไว้ในตัวแปร first_cost
🟡 ประยุกต์
ลูกค้าจากช่องทาง promo (ใช้ .loc) แสดง customer_id กับ signup_date เอาแค่ 5 แถวแรกตามที่ปรากฏในตาราง เก็บไว้ในตัวแปร result
ตั้ง order_id เป็น index แล้วดึงข้อมูลออเดอร์หมายเลข 1 แสดง customer_id กับ status เก็บไว้ในตัวแปร result
สินค้าที่ราคามากกว่า 10000 บาท (ใช้ .loc) แสดงเฉพาะคอลัมน์ category เก็บไว้ในตัวแปร result
🔴 ท้าทาย
เรียงสินค้าตามราคาจากถูกไปแพง รีเซ็ต index ก่อน แล้วใช้ .loc[0:2] ดึง 3 แถวแรก (สังเกตว่า .loc รวมขอบท้าย) แสดง product_name, price เก็บไว้ในตัวแปร result
Quiz
สรุป
- .loc อ้างอิงด้วย label ส่วน .iloc อ้างอิงด้วยตำแหน่ง (เลขลำดับ)
- .loc[a:b] รวมขอบท้าย (inclusive) ต่างจาก .iloc[a:b]/slice ปกติที่ไม่รวม (exclusive)
- เลือกทั้งแถวและคอลัมน์พร้อมกันด้วย .loc[แถว, คอลัมน์] หรือ .iloc[แถว, คอลัมน์] ในคำสั่งเดียว
คำถามสัมภาษณ์
ทำไมควรใช้ .loc[เงื่อนไข, คอลัมน์] = ค่า แทนการเขียน df[เงื่อนไข][คอลัมน์] = ค่า เวลาจะแก้ไขข้อมูล
คำตอบสั้นๆ ในบทนี้ (อธิบายเต็มในบทที่ 7 เรื่อง cleaning): df[เงื่อนไข] อาจได้ DataFrame ใหม่ที่เป็นแค่สำเนา
ไม่ใช่ตัวข้อมูลจริง การแก้ไขต่อจากนั้น ([คอลัมน์] = ค่า) จึงอาจไม่มีผลอะไรเลยกับตารางต้นฉบับ
โดยไม่มี error หรือ warning เตือนด้วย ทางที่ปลอดภัยเสมอคือใช้ .loc[เงื่อนไข, คอลัมน์] = ค่า ในคำสั่งเดียว