φυβλαςのβλογ
บล็อกของ phyblas



จัดการข้อมูลด้วย pandas เบื้องต้น บทที่ ๔: การคัดกรองข้อมูล
เขียนเมื่อ 2016/09/25 13:50
งานสำคัญอย่างหนึ่งที่มักจะต้องทำในขั้นตอนแรกๆของการจัดการข้อมูลก็คือการคัดกรองข้อมูล เพราะบางครั้งเราก็ไม่ได้ต้องการใช้ข้อมูลทั้งหมดที่ถูกเตรียมไว้ หรือข้อมูลบางส่วนอาจบกพร่องไม่เหมาะแก่การใช้ก็ต้องคัดออก



การเลือกเฉพาะคอลัมน์หรือแถวที่ต้องการด้วยลิสต์ของดัชนี
ในบทแรกได้พูดถึงการคัดข้อมูลเฉพาะแถวที่ต้องการในซีรีส์ไปแล้ว สำหรับเดตาเฟรมเองก็ใช้วิธีการเดียวกัน คือการใช้ดัชนีเป็นลิสต์ของชื่อแถวที่ต้องการเอา

เพียงแต่ว่าเดตาเฟรมนั้นนอกจากมีแถวแล้วก็ยังมีคอลัมน์ด้วย จึงซับซ้อนกว่า และต้องแยกแยะให้ดีว่าจะเลือกจากแถวหรือคอลัมน์

กรณีที่ต้องการคัดเลือกแค่คอลัมน์ที่ต้องการก็ให้ใส่ดัชนีเป็นลิสต์ของคอลัมน์ได้เลย

ตัวอย่าง มีตารางข้อมูลของโปเกมอนซึ่งประกอบไปด้วย สายพันธุ์, ชนิด, ส่วนสูง และน้ำหนัก
import pandas as pd
pokemon = pd.DataFrame([
        ['นาเอเทิล','พืช',0.4,10.2],
        ['ฮิโกะซารุ','ไฟ',0.5,6.2],
        ['พจจามะ','น้ำ',0.4,5.2],
        ['มุกกุรุ','ธรรมดา,บิน',0.3,2.0]],
    columns=['สายพันธุ์','ชนิด','ส่วนสูง','น้ำหนัก'],
    index=[387,390,393,396])
print(pokemon)



ได้
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
387 นาเอเทิล พืช 0.4 10.2
390 ฮิโกะซารุ ไฟ 0.5 6.2
393 พจจามะ น้ำ 0.4 5.2
396 มุกกุรุ ธรรมดา,บิน 0.3 2.0

จากนั้นลองตัดชนิดออกไป เอาแค่สายพันธุ์, ส่วนสูง และน้ำหนัก
pokemon = pokemon[['สายพันธุ์','ส่วนสูง','น้ำหนัก']]
print(pokemon)

ได้
  สายพันธุ์ ส่วนสูง น้ำหนัก
387 นาเอเทิล 0.4 10.2
390 ฮิโกะซารุ 0.5 6.2
393 พจจามะ 0.4 5.2
396 มุกกุรุ 0.3 2.0

กรณีนี้จะต่างจากซีรีส์ ถ้าเป็นซีรีส์การใส่ดัชนีไปโดยตรงจะเป็นการคัดเลือกจากแถว

สำหรับเดตาเฟรมหากต้องการคัดเลือกจากแถวให้ใช้ .loc

ตัวอย่าง
pokemon = pd.DataFrame([
        ['ฮายาชิงาเมะ','พืช',1.1,97.0],
        ['โมวกะซารุ','ไฟ,ต่อสู้',0.9,22.0],
        ['พตไทชิ','น้ำ',0.8,23.0],
        ['มุกุเบิร์ด','ธรรมดา,บิน',0.6,15.5],
        ['บีดารุ','ธรรมดา,น้ำ',1.0,31.5]],
    columns=['สายพันธุ์','ชนิด','ส่วนสูง','น้ำหนัก'],
    index=[388,391,394,397,400])
print(pokemon)



ได้
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
388 ฮายาชิงาเมะ พืช 1.1 97.0
391 โมวกะซารุ ไฟ,ต่อสู้ 0.9 22.0
394 พตไทชิ น้ำ 0.8 23.0
397 มุกุเบิร์ด ธรรมดา,บิน 0.6 15.5
400 บีดารุ ธรรมดา,น้ำ 1.0 31.5

เลือกเอาเฉพาะบางแถว
pokemon = pokemon.loc[[388,391,394]]
print(pokemon)

ได้
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
388 ฮายาชิงาเมะ พืช 1.1 97.0
391 โมวกะซารุ ไฟ,ต่อสู้ 0.9 22.0
394 พตไทชิ น้ำ 0.8 23.0

หรืออาจใช้ iloc เพื่อใช้ดัชนีเป็นลำดับของแถวก็ได้ เช่นถ้าเขียนแบบนี้จะได้ผลเหมือนกัน
pokemon = pokemon.iloc[[0,1,2]]

ผลที่ได้จะออกมาเป็นเดตาเฟรมเสมอหากเราใส่เป็นลิสต์ ต่อให้เป็นลิสต์ที่มีเพียงตัวเดียวก็ตาม เช่น
print(pokemon.iloc[[0]])

ได้
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
388 ฮายาชิงาเมะ พืช 1.1 97.0

จะเห็นว่าแม้ข้อมูลจะเหลือแค่แถวเดียวแต่ก็ยังเป็นเดตาเฟรมอยู่

ซึ่งจะต่างจากกรณีที่ดัชนีเป็นเลขเดี่ยวไม่ใช่ลิสต์ ซึ่งจะให้ผลเป็นซีรีส์ของข้อมูลของแถวนั้น
print(pokemon.iloc[0])

ได้
สายพันธุ์    ฮายาชิงาเมะ
ชนิด                 พืช
ส่วนสูง              1.1
น้ำหนัก               97
Name: 388, dtype: object



การคัดกรองจากเงื่อนไข
เช่นเดียวกับซีรีส์ เดตาเฟรมก็สามารถใช้ลิสต์ของบูลมาเป็นดัชนีได้เพื่อที่จะคัดกรองสมาชิก

ตัวอย่างเช่น
pokemon = pd.DataFrame([
        ['โคโรโบชิ','แมลง',0.3,2.2],
        ['โคโรท็อก','แมลง',1.0,25.5],
        ['โคลิงก์','ไฟฟ้า',0.5,9.5],
        ['ลุกซิโอ','ไฟฟ้า',0.9,30.5],
        ['เรินโทราร์','ไฟฟ้า',1.4,42.0]],
    columns=['สายพันธุ์','ชนิด','ส่วนสูง','น้ำหนัก'],
    index=[401,402,403,404,405])
print(pokemon)
print('--------------------')
print(pokemon[[True,False,False,True,False]])



ได้
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
401 โคโรโบชิ แมลง 0.3 2.2
402 โคโรท็อก แมลง 1.0 25.5
403 โคลิงก์ ไฟฟ้า 0.5 9.5
404 ลุกซิโอ ไฟฟ้า 0.9 30.5
405 เรินโทราร์ ไฟฟ้า 1.4 42.0
--------------------
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
401 โคโรโบชิ แมลง 0.3 2.2
404 ลุกซิโอ ไฟฟ้า 0.9 30.5

สังเกตได้ว่ากรณีที่ดัชนีเป็นลิสต์ของบูลจะเป็นการคัดกรองโดยดูจากแถว ไม่ใช่คอลัมน์ ต่อให้ไม่ได้ใส่ .loc หรือ .iloc ไปก็ตาม ซึ่งจะต่างจากกรณีอื่น ดังนั้นต้องระวังสับสน

เพียงแต่ว่าจะเติม .loc หรือ .iloc ไปก็ได้เหมือนกัน เช่น
print(pokemon.iloc[[True,False,False,True,False]])

ผลที่ได้จะไม่ต่างกันกับไม่ใส่

นอกจากลิสต์แล้วจะใช้เป็นข้อมูลชนิดกลุ่มแบบอื่นๆเช่นอาเรย์หรือซีรีส์ก็ได้เช่นกัน เช่นใช้ซีรีส์ แต่กรณีที่เป็นซีรีส์นั้นจะต้องเตรียมซีรีส์ที่มีชื่อแถวเหมือนกัน

เช่นลองใช้ซีรีส์ตามนี้ผลที่ได้จะเหมือนกับตัวอย่างที่แล้วที่ใช้ลิสต์
tfftf = pd.Series([True,False,False,True,False],index=[401,402,403,404,405])
print(pokemon[tfftf])

ซึ่งซีรีส์ของบูลในลักษณะเช่นนี้สามารถเตรียมได้ง่ายโดยการนำซีรีส์มาเข้าในนิพจน์ที่มี == > < >= <=

คอลัมน์แต่ละคอลัมน์ของเดตาเฟรมเมื่อแยกออกมาก็เป็นซีรีส์ ตัวอย่างเช่นลองดูที่คอลัมน์ "ชนิด"
print(pokemon['ชนิด'])

ได้
401     แมลง
402     แมลง
403    ไฟฟ้า
404    ไฟฟ้า
405    ไฟฟ้า
Name: ชนิด, dtype: object

ถ้าเราใช้คอลัมน์นี้มาตั้งเงื่อนไขว่าให้มีค่าเท่ากับ "ไฟฟ้า"
print(pokemon['ชนิด']=='ไฟฟ้า')

แบบนี้จะได้
401    False
402    False
403     True
404     True
405     True
Name: ชนิด, dtype: bool

และเมื่อเราเอาซีรีส์ที่ได้จากเงื่อนไขนี้ไปใช้เป็นดัชนีของเดตาเฟรมก็จะเป็นการคัดกรองเอาเฉพาะโปเกมอนที่เป็นชนิดไฟฟ้า
print(pokemon[pokemon['ชนิด']=='ไฟฟ้า'])

ได้
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
403 โคลิงก์ ไฟฟ้า 0.5 9.5
404 ลุกซิโอ ไฟฟ้า 0.9 30.5
405 เรินโทราร์ ไฟฟ้า 1.4 42.0

หรือถ้าจะคัดกรองโดยคัดจากน้ำหนักก็ได้
print(pokemon[pokemon['น้ำหนัก']<20])

ได้
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
401 โคโรโบชิ แมลง 0.3 2.2
403 โคลิงก์ ไฟฟ้า 0.5 9.5

นี่เป็นวิธีการคัดกรองที่มีประสิทธิภาพและใช้บ่อยมากที่สุด

การสร้างซีรีส์ของบูลเพื่อคัดกรองนั้นอาจสร้างขึ้นจากเมธอดบางตัวได้

เช่นกรณีที่จะตั้งเงื่อนไขว่าจะคัดเอาแถวที่ข้อมูลในนั้นอยู่ภายในลิสต์ที่เตรียมไว้ก็อาจใช้เมธอด isin ซึ่งมีความหมายในทำนองเดียวกับคำสั่ง in คือใช้ตรวจสอบว่าออบเจ็กต์นั้นๆเป็นสมาชิกอยู่ในลิสต์หรือเปล่าแล้วคืนค่า True หรือ False

ตัวอย่างเช่นสมมุติว่ามีข้อมูลโปเกมอนอยู่จำนวนหนึ่งที่เป็นชนิดต่างๆ แล้วต้องการคัดเอาที่เป็นชนิดน้ำและไฟฟ้าเท่านั้น แบบนี้ก็อาจเหมาะที่จะใช้ isin
pokemon = pd.DataFrame([
        ['ปาจิริสึ','ไฟฟ้า',0.4,3.9],
        ['บุยเซล','น้ำ',0.7,29.5],
        ['แชริมโบะ','พืช',0.4,3.3],
        ['คาระนากุชิ','น้ำ',0.3,6.3],
        ['ฟุวันเต','ผี,บิน',0.4,1.2]],
    columns=['สายพันธุ์','ชนิด','ส่วนสูง','น้ำหนัก'],
    index=[417,418,420,422,425])
print(pokemon)
print('----------------------')
print(pokemon['ชนิด'].isin(['น้ำ','ไฟฟ้า']))
print('----------------------')
print(pokemon[pokemon['ชนิด'].isin(['น้ำ','ไฟฟ้า'])])



ได้
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
417 ปาจิริสึ ไฟฟ้า 0.4 3.9
418 บุยเซล น้ำ 0.7 29.5
420 แชริมโบะ พืช 0.4 3.3
422 คาระนากุชิ น้ำ 0.3 6.3
425 ฟุวันเต ผี,บิน 0.4 1.2
----------------------
417     True
418     True
420    False
422     True
425    False
Name: ชนิด, dtype: bool
----------------------
  สายพันธุ์ ชนิด ส่วนสูง น้ำหนัก
417 ปาจิริสึ ไฟฟ้า 0.4 3.9
418 บุยเซล น้ำ 0.7 29.5
422 คาระนากุชิ น้ำ 0.3 6.3

กรณีนี้หากต้องการแค่โปเกมอนน้ำก็อาจเขียนเป็น pokemon[pokemon['ชนิด']=='น้ำ'] ถ้าต้องการไฟฟ้าก็เป็น pokemon[pokemon['ชนิด']=='ไฟฟ้า'] แต่เมื่อต้องการทั้งสองอย่างพร้อมกัน การเขียนแบบที่ว่ามานี้ก็จะเหมาะกว่า



การรับมือกับข้อมูลที่อาจไม่มีอยู่
หากมีลิสต์ของดัชนีหรือชื่อคอลัมน์อยู่จำนวนหนึ่งและต้องการใช้เพื่อคัดเอาข้อมูลในเดตาเฟรมที่ที่มีดัชนีหรือชื่อคอลัมน์ตามนั้นแต่ปรากฏว่าชื่อหรือค่าที่ใส่ลงไปบางส่วนไม่มีอยู่ในนั้น กรณีแบบนี้แบบนี้ก็จะเกิดข้อผิดพลาดขึ้นทันที

เช่นเราต้องการเข้าถึงข้อมูลสายพันธุ์, ส่วนสูง และน้ำหนักของโปเกมอนจำนวนหนึ่ง แต่ว่าข้อมูลในเดตาเฟรมที่เตรียมไว้ไม่มีข้อมูลส่วนสูง
pokemon = pd.DataFrame([
        ['อุโซฮาจิ','หิน',15.0],
        ['พิมปุกุ','ธรรมดา',24.4],
        ['มิการุเงะ','ผี,มาร',108.0],
        ['กอนเบ','ธรรมดา',105.0]],
    columns=['สายพันธุ์','ชนิด','น้ำหนัก'],
    index=[438,440,442,446])
print(pokemon)



ได้
  สายพันธุ์ ชนิด น้ำหนัก
438 อุโซฮาจิ หิน 15.0
440 พิมปุกุ ธรรมดา 24.4
442 มิการุเงะ ผี,มาร 108.0
446 กอนเบ ธรรมดา 105.0

หากลองพิมพ์
print(pokemon[['สายพันธุ์','ส่วนสูง','น้ำหนัก']])

จะได้
KeyError: "['ส่วนสูง'] not in index"

กรณีแบบนี้อาจแก้ปัญหาได้โดยใช้ .loc ได้ คือเขียนเป็น
print(pokemon.loc[:,['สายพันธุ์','ส่วนสูง','น้ำหนัก']])

ได้
  สายพันธุ์ ส่วนสูง น้ำหนัก
438 อุโซฮาจิ NaN 15.0
440 พิมปุกุ NaN 24.4
442 มิการุเงะ NaN 108.0
446 กอนเบ NaN 105.0

แบบนี้ก็จะไม่เกิดข้อผิดพลาดขึ้น แต่จะเห็นว่ามีแถวข้อมูลส่วนสูงซึ่งมี NaN ปรากฏขึ้นมา

กรณีที่ใช้เพื่อเข้าถึงข้อมูลตามแถวก็ให้ผลลักษณะเดียวกัน
print(pokemon.loc[[438,439,440,441]])

ได้
  สายพันธุ์ ชนิด น้ำหนัก
438 อุโซฮาจิ หิน 15.0
439 NaN NaN NaN
440 พิมปุกุ ธรรมดา 24.4
441 NaN NaN NaN

วิธีนี้ถึงจะไม่เกิดข้อผิดพลาด แต่ก็ทำให้มีแถวที่มี NaN ปรากฏขึ้นมา ซึ่งบางทีมันก็อาจไม่จำเป็นเพราะยังไงก็ไม่มีข้อมูลอะไรเลยอยู่ดี

กรณีที่ไม่ต้องการให้มีแถวที่ไม่มีข้อมูลโผล่ขึ้นมาเลยอาจใช้วิธีอื่น นั่นคืออาศัยเมธอด isin กับชื่อคอลัมน์หรือชื่อแถวของเดตาเฟรม

เช่นสำหรับแถวอาจเขียนเป็น .loc[เดตาเฟรม.index.isin()] เช่น
print(pokemon.loc[pokemon.index.isin([438,439,440,441])])

ได้
  สายพันธุ์ ชนิด น้ำหนัก
438 อุโซฮาจิ หิน 15.0
440 พิมปุกุ ธรรมดา 24.4

สำหรับคอลัมน์เขียนเป็น .loc[:,เดตาเฟรม.columns.isin()] เช่น
print(pokemon.loc[:,pokemon.columns.isin(['สายพันธุ์','ส่วนสูง','น้ำหนัก'])])

ได้
  สายพันธุ์ น้ำหนัก
438 อุโซฮาจิ 15.0
440 พิมปุกุ 24.4
442 มิการุเงะ 108.0
446 กอนเบ 105.0



อ้างอิง


<< บทที่แล้ว      บทถัดไป >>
หน้าสารบัญ


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> pandas

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
python
-- numpy
-- matplotlib

-- pandas
-- pytorch
maya
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
เรียนภาษาจีน
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

หลักการเขียนทับศัพท์ภาษาจีนกวางตุ้ง
การใช้ unix shell เบื้องต้น ใน linux และ mac
หลักการเขียนทับศัพท์ภาษาจีนกลาง
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
บันทึกการเที่ยวสวีเดน 1-12 พ.ค. 2014
แนะนำองค์การวิจัยและพัฒนาการสำรวจอวกาศญี่ปุ่น (JAXA)
เล่าประสบการณ์ค่ายอบรมวิชาการทางดาราศาสตร์โดยโซวเคนได 10 - 16 พ.ย. 2013
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
บันทึกการเที่ยวญี่ปุ่นครั้งแรกในชีวิต - ทุกอย่างเริ่มต้นที่สนามบินนานาชาติคันไซ
หลักการเขียนทับศัพท์ภาษาญี่ปุ่น
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ
ทำไมถึงอยากมาเรียนต่อนอก
เหตุผลอะไรที่ต้องใช้ภาษาวิบัติ?

ไทย

日本語

中文