Pertemuan 2 : Data Cleaning with Pandas

Handling Dirty Data using Pandas
Published

April 15, 2024

Kembali ke EDA

Gathering Data

Data yang kita terima seringkali tidak berupa 1 tabel yang lengkap berisi seluruh informasi yang dibutuhkan. Terkadang kita perlu menggabungkan 2 atau lebih data yang saling berhubungan. Pandas memiliki beberapa fungsi yang dapat kita gunakan untuk menggabungkan beberapa data tersebut.

Concatenate & Merge

Concatenate

Concatenate digunakan untuk menggabungkan 2 atau lebih series/dataframe. Argumen axis= digunakan untuk mengatur opsi penggabungan data menurut index baris atau index kolom. Berikut contoh penggunaan pada 2 series :

import numpy as np
import pandas as pd

series1 = pd.Series(['a','b','c'])
series2 = pd.Series(['x','y','z'])

axis=0 (default) akan menggabungkan data pada index baris.

pd.concat([series1,series2], axis=0)
0    a
1    b
2    c
0    x
1    y
2    z
dtype: object

axis=1 akan menggabungkan data pada index kolom.

pd.concat([series1,series2], axis=1)
0 1
0 a x
1 b y
2 c z

ignore_index=True akan mengabaikan index awal dari masing-masing data sehingga hasil penggabungan memiliki index baru.

pd.concat([series1,series2], ignore_index=True)
0    a
1    b
2    c
3    x
4    y
5    z
dtype: object

Kita dapat menambahkan keys sebagai penanda dari masing-masing series sebelum digabungkan.

pd.concat([series1,series2], keys=['Series 1','Series 2'])
Series 1  0    a
          1    b
          2    c
Series 2  0    x
          1    y
          2    z
dtype: object
Tip

Hasil penggabungan dengan argumen keys= akan menambahkan keys sebagai index gabungan, sehingga pada contoh di atas, index dari masing-masing value adalah sebuah tuple yang merupakan pasangan index gabungan dan index masing-masing.

pd.concat([series1,series2], keys=['Series 1','Series 2']).index
MultiIndex([('Series 1', 0),
            ('Series 1', 1),
            ('Series 1', 2),
            ('Series 2', 0),
            ('Series 2', 1),
            ('Series 2', 2)],
           )

Berikut contoh penggunaan pada DataFrame :

df1=pd.DataFrame({'col 1':['a','b','c'],'col 2':[0,1,2]})
df2=pd.DataFrame({'col 1':['x','y','z'],'col 2':[4,5,6]})
df1
col 1 col 2
0 a 0
1 b 1
2 c 2
df2
col 1 col 2
0 x 4
1 y 5
2 z 6

axis=0 (default) akan menggabungkan data pada index baris.

pd.concat([df1,df2])
col 1 col 2
0 a 0
1 b 1
2 c 2
0 x 4
1 y 5
2 z 6

axis=1 akan menggabungkan data pada index kolom.

pd.concat([df1,df2], axis=1)
col 1 col 2 col 1 col 2
0 a 0 x 4
1 b 1 y 5
2 c 2 z 6

Perhatikan bahwa nama kolom df1 dan df2 sama. Misalkan kita menggabungkan 2 dataframe dengan nama kolom yang berbeda.

df3=pd.DataFrame({'col 2':[3,4,5],'col 3':['m','n','o']})
df3
col 2 col 3
0 3 m
1 4 n
2 5 o

Concatenate pada DataFrame melihat index kolom sebagai acuan untuk penggabungan pada axis=0 (baris).

pd.concat([df1,df3])
col 1 col 2 col 3
0 a 0 NaN
1 b 1 NaN
2 c 2 NaN
0 NaN 3 m
1 NaN 4 n
2 NaN 5 o

Karena df1 dan df3 memiliki nama kolom yang berbeda, maka terjadi penggabungan baris sekaligus kolom.


Untuk kolom yang beririsan, bisa menggunakan argumen join= untuk mengatur bagaimana penggabungan dilakukan (pada keseluruhan data atau pada data yang beririsan saja)

pd.concat([df1,df3], join='inner') # df1 ⋂ df3
col 2
0 0
1 1
2 2
0 3
1 4
2 5
pd.concat([df1,df3], join='outer') # df1 ⋃ df3
col 1 col 2 col 3
0 a 0 NaN
1 b 1 NaN
2 c 2 NaN
0 NaN 3 m
1 NaN 4 n
2 NaN 5 o

Merge

Fungsi merge pada pandas digunakan untuk menggabungkan 2 atau lebih dataframe berdasarkan index kolom tertentu.

karyawan = pd.DataFrame({'id':[1,2,3,4],'nama':['Joko','Alvin','Rafi','Lita']})
karyawan
id nama
0 1 Joko
1 2 Alvin
2 3 Rafi
3 4 Lita
gaji = pd.DataFrame({'id':[2,1,3,5,4,6],'gaji':[100.0,200.0,300.0,400.0,500.0,600.0]})
gaji
id gaji
0 2 100.0
1 1 200.0
2 3 300.0
3 5 400.0
4 4 500.0
5 6 600.0
pd.merge(karyawan, gaji, on='id')
id nama gaji
0 1 Joko 200.0
1 2 Alvin 100.0
2 3 Rafi 300.0
3 4 Lita 500.0

Data nama karyawan dan gaji digabungkan dalam 1 dataframe, dengan nilai-nilai pada kolom id sebagai acuan.

Merge & Join

Pada modul ini, hanya dibahas mengenai dasar penggunaan fungsi merge untuk menggabungkan dataset. Untuk penggunaan lebih spesifik dengan argumen left=, right=, left_on=, right_on= dan how= akan dibahas pada materi Data Wrangling

Assessing Data

Setelah memiliki data yang komplit, langkah selanjutnya adalah mengidentifikasi validitas data yang kita punya. Apakah data yang kita miliki sudah cukup baik? Apakah sudah bisa dilakukan analisis pada data yang ada? Perlukah perubahan dan perbaruan data?

Pertama, kita perlu melihat keberadaan data yang buruk dalam kumpulan data kita.

Data yang buruk dapat berupa:

  • Data dalam format yang salah (Data integer terbaca sebagai suatu string)
  • Sel yang kosong (Missing)
  • Duplikat (Data yang sama muncul lebih dari 1 kali)
  • Data yang salah (Data yang tidak masuk akal. Misalnya seseorang berumur 600 tahun)

df.info()

Method .info() dapat digunakan untuk melihat informasi dasar suatu dataframe seperti jumlah entri keseluruhan, nama kolom, jumlah nilai non-null tiap kolom, tipe data tiap kolom hingga penggunaan memori suatu dataframe

Misalkan kita gunakan dataset pokemon pada modul sebelumnya,

df = pd.read_csv('https://raw.githubusercontent.com/farhanage/dataset-for-study/main/pokemon_data.csv')
df.head()
# Name Type 1 Type 2 HP Attack Defense Sp. Atk Sp. Def Speed Generation Legendary
0 1 Bulbasaur Grass Poison 45 49 49 65 65 45 1 False
1 2 Ivysaur Grass Poison 60 62 63 80 80 60 1 False
2 3 Venusaur Grass Poison 80 82 83 100 100 80 1 False
3 3 VenusaurMega Venusaur Grass Poison 80 100 123 122 120 80 1 False
4 4 Charmander Fire NaN 39 52 43 60 50 65 1 False
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 800 entries, 0 to 799
Data columns (total 12 columns):
 #   Column      Non-Null Count  Dtype 
---  ------      --------------  ----- 
 0   #           800 non-null    int64 
 1   Name        800 non-null    object
 2   Type 1      800 non-null    object
 3   Type 2      414 non-null    object
 4   HP          800 non-null    int64 
 5   Attack      800 non-null    int64 
 6   Defense     800 non-null    int64 
 7   Sp. Atk     800 non-null    int64 
 8   Sp. Def     800 non-null    int64 
 9   Speed       800 non-null    int64 
 10  Generation  800 non-null    int64 
 11  Legendary   800 non-null    bool  
dtypes: bool(1), int64(8), object(3)
memory usage: 69.7+ KB

Missing Values

Terdapat 2 tipe missing value.

  1. Data bernilai NaN (Not a Number)
  2. Data bernilai 0 (Null)
Null

Data bernilai 0 (Null) tidak selalu bersifat sebagai data yang hilang, bisa juga data memang memiliki data yang bernilai 0. Oleh karena itu, penting bagi kita untuk mengetahui konteks dari data yang dianalisis.


df = pd.DataFrame({"Evan" : [np.nan,100,95,94,99],"Boy" : [100,np.nan,95,99,94],"Maxwell" : [95,100,99,np.nan,94]})
df
Evan Boy Maxwell
0 NaN 100.0 95.0
1 100.0 NaN 100.0
2 95.0 95.0 99.0
3 94.0 99.0 NaN
4 99.0 94.0 94.0

Untuk melihat data mana saja yang mengandung value NaN (Not a Number), kita gunakan method .isna() atau .isnull(). (Kedua method ini memiliki fungsi yang sama dan dapat digunakan secara bergantian/salah satu saja)

df.isna()
Evan Boy Maxwell
0 True False False
1 False True False
2 False False False
3 False False True
4 False False False

Untuk melihat jumlah value NaN pada data, tambahkan method .sum() pada kode di atas.

df.isna().sum()
Evan       1
Boy        1
Maxwell    1
dtype: int64
Method .sum()

Method .sum() digunakan untuk menjumlahkan nilai-nilai pada tiap kolom dataframe (Juga dalam suatu Series).

Untuk melihat entri-entri yang memiliki nilai NaN pada kolom tertentu, lakukan filtering pada dataframe dengan df['<nama-kolom>'].isna() sebagai kondisi yang diinginkan.

df[df['Evan'].isna()]   # Entri yang memiliki nilai `NaN` pada kolom `Evan`
Evan Boy Maxwell
0 NaN 100.0 95.0

Duplicates

Data duplikat pada dataframe adalah entri yang memiliki nilai yang sama pada setiap kolom. Jika terdapat setidaknya 1 nilai kolom yang berbeda antara 2 entri, data tersebut bukanlah sebuah duplikat.

df = pd.DataFrame({
    "id" : [1,2,3,4,3,6],
    "Karyawan" : ['Joko','Alvin','Rafi','Lita','Rafi','Jennie'],
    "Gaji" : [100.0, 200.0, 300.0, 400.0, 300.0, 600.0]})
df
id Karyawan Gaji
0 1 Joko 100.0
1 2 Alvin 200.0
2 3 Rafi 300.0
3 4 Lita 400.0
4 3 Rafi 300.0
5 6 Jennie 600.0

Untuk melihat data yang memiliki duplikat pada dataframe, kita gunakan method .duplicated().

df.duplicated()
0    False
1    False
2    False
3    False
4     True
5    False
dtype: bool

Perhatikan bahwa data yang terbaca sebagai duplikat adalah data yang muncul setelah kemunculan data pertama kali (data duplikat pertama tidak dianggap sebagai duplikat)

Dengan cara yang sama seperti pada Missing Value, kita bisa menggunakan method .sum() untuk melihat jumlah data duplikat pada suatu dataframe.

df.duplicated().sum()
1

Untuk melihat entri-entri yang memiliki nilai duplikat pada kolom tertentu, lakukan filtering pada dataframe dengan df['<nama-kolom>'].duplicated() sebagai kondisi yang diinginkan.

df[df['id'].duplicated()]   # Entri yang memiliki nilai `id` duplikat
id Karyawan Gaji
4 3 Rafi 300.0

Descriptive Statistics

Untuk mengidentifikasi apakah terdapat data yang salah, jika kita perlu tahu konteks data tersebut. Seperti bagaimana cara data diperoleh? Apakah ada batas-batas nilai pada variabel-variabel tertentu?

Salah satu cara mudah untuk mengidentifikasi persebaran suatu data adalah dengan melihat statistik deskriptif suatu data. Kita bisa menggunakan method .describe() untuk melihat ukuran persebaran data dari masing-masing variabel pada suatu dataframe.

df = pd.read_csv('https://raw.githubusercontent.com/farhanage/dataset-for-study/main/pokemon_data.csv')
df.head()
# Name Type 1 Type 2 HP Attack Defense Sp. Atk Sp. Def Speed Generation Legendary
0 1 Bulbasaur Grass Poison 45 49 49 65 65 45 1 False
1 2 Ivysaur Grass Poison 60 62 63 80 80 60 1 False
2 3 Venusaur Grass Poison 80 82 83 100 100 80 1 False
3 3 VenusaurMega Venusaur Grass Poison 80 100 123 122 120 80 1 False
4 4 Charmander Fire NaN 39 52 43 60 50 65 1 False
df.describe()
# HP Attack Defense Sp. Atk Sp. Def Speed Generation
count 800.000000 800.000000 800.000000 800.000000 800.000000 800.000000 800.000000 800.00000
mean 362.813750 69.258750 79.001250 73.842500 72.820000 71.902500 68.277500 3.32375
std 208.343798 25.534669 32.457366 31.183501 32.722294 27.828916 29.060474 1.66129
min 1.000000 1.000000 5.000000 5.000000 10.000000 20.000000 5.000000 1.00000
25% 184.750000 50.000000 55.000000 50.000000 49.750000 50.000000 45.000000 2.00000
50% 364.500000 65.000000 75.000000 70.000000 65.000000 70.000000 65.000000 3.00000
75% 539.250000 80.000000 100.000000 90.000000 95.000000 90.000000 90.000000 5.00000
max 721.000000 255.000000 190.000000 230.000000 194.000000 230.000000 180.000000 6.00000

Namun, metode ini hanya dapat digunakan pada data numerik. Sehingga untuk data non-numerik, perlu pemahaman lebih lanjut mengenai konteks data dan metode yang digunakan untuk mengonfirmasi validitas data.

Cleaning Data

Memperbaiki Format Data yang Salah

Terdapat lebih dari 1 cara untuk memperbaiki format data yang salah. Tidak disalahkan bagi anda untuk mencarinya di internet sendiri. Silakan merujuk pada berbagai sumber. Salah satunya adalah jawaban dari pertanyaan pada forum StackOverflow berikut : Link

Mengimputasi sel yang kosong

df.fillna(value='<value>', inplace=True)

Menghapus data duplikat

df.drop_duplicates(inplace=True)