Data Analyst › pandas

.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 โดยอ้างอิงด้วย "ตำแหน่ง" ไม่ใช่ชื่อคอลัมน์หรือเงื่อนไข

  1. .iloc[0] ดึงแถวแรก (ตำแหน่ง 0) ทั้งแถว ได้ผลเป็น Series

    Python

ดึงข้อมูลด้วยเงื่อนไข พร้อมเลือกคอลัมน์ (.loc)

อยากดูเฉพาะสินค้าหมวด Books และแสดงแค่บางคอลัมน์

  1. .loc[เงื่อนไข] กรองแถวด้วยเงื่อนไข boolean เหมือน df[เงื่อนไข] ทั่วไป

    Python

เติมช่องว่าง

แทน ___ ด้วยโค้ดที่ถูกต้อง แล้วกดตรวจคำตอบ

ยังไม่ได้ทำ

ดึงเฉพาะลูกค้าจากเมือง 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

1. .loc กับ .iloc ต่างกันยังไง
2. .loc[0:2] กับ .iloc[0:2] ต่างกันยังไง
3. จะเลือกทั้งแถวและคอลัมน์พร้อมกันต้องเขียนยังไง

สรุป

  • .loc อ้างอิงด้วย label ส่วน .iloc อ้างอิงด้วยตำแหน่ง (เลขลำดับ)
  • .loc[a:b] รวมขอบท้าย (inclusive) ต่างจาก .iloc[a:b]/slice ปกติที่ไม่รวม (exclusive)
  • เลือกทั้งแถวและคอลัมน์พร้อมกันด้วย .loc[แถว, คอลัมน์] หรือ .iloc[แถว, คอลัมน์] ในคำสั่งเดียว

คำถามสัมภาษณ์

ทำไมควรใช้ .loc[เงื่อนไข, คอลัมน์] = ค่า แทนการเขียน df[เงื่อนไข][คอลัมน์] = ค่า เวลาจะแก้ไขข้อมูล

คำตอบสั้นๆ ในบทนี้ (อธิบายเต็มในบทที่ 7 เรื่อง cleaning): df[เงื่อนไข] อาจได้ DataFrame ใหม่ที่เป็นแค่สำเนา ไม่ใช่ตัวข้อมูลจริง การแก้ไขต่อจากนั้น ([คอลัมน์] = ค่า) จึงอาจไม่มีผลอะไรเลยกับตารางต้นฉบับ โดยไม่มี error หรือ warning เตือนด้วย ทางที่ปลอดภัยเสมอคือใช้ .loc[เงื่อนไข, คอลัมน์] = ค่า ในคำสั่งเดียว