import numpy as np
import pandas as pd
= pd.Series(['a','b','c'])
series1 = pd.Series(['x','y','z']) series2
Pertemuan 2 : Data Cleaning with Pandas
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 :
axis=0 (default)
akan menggabungkan data pada index baris.
=0) pd.concat([series1,series2], axis
0 a
1 b
2 c
0 x
1 y
2 z
dtype: object
axis=1
akan menggabungkan data pada index kolom.
=1) pd.concat([series1,series2], axis
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.
=True) pd.concat([series1,series2], ignore_index
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.
=['Series 1','Series 2']) pd.concat([series1,series2], keys
Series 1 0 a
1 b
2 c
Series 2 0 x
1 y
2 z
dtype: object
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.
=['Series 1','Series 2']).index pd.concat([series1,series2], keys
MultiIndex([('Series 1', 0),
('Series 1', 1),
('Series 1', 2),
('Series 2', 0),
('Series 2', 1),
('Series 2', 2)],
)
Berikut contoh penggunaan pada DataFrame :
=pd.DataFrame({'col 1':['a','b','c'],'col 2':[0,1,2]})
df1=pd.DataFrame({'col 1':['x','y','z'],'col 2':[4,5,6]}) df2
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.
=1) pd.concat([df1,df2], axis
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.
=pd.DataFrame({'col 2':[3,4,5],'col 3':['m','n','o']})
df3 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)
='inner') # df1 ⋂ df3 pd.concat([df1,df3], join
col 2 | |
---|---|
0 | 0 |
1 | 1 |
2 | 2 |
0 | 3 |
1 | 4 |
2 | 5 |
='outer') # df1 ⋃ df3 pd.concat([df1,df3], join
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.
= pd.DataFrame({'id':[1,2,3,4],'nama':['Joko','Alvin','Rafi','Lita']})
karyawan karyawan
id | nama | |
---|---|---|
0 | 1 | Joko |
1 | 2 | Alvin |
2 | 3 | Rafi |
3 | 4 | Lita |
= pd.DataFrame({'id':[2,1,3,5,4,6],'gaji':[100.0,200.0,300.0,400.0,500.0,600.0]})
gaji 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 |
='id') pd.merge(karyawan, gaji, on
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.
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,
= pd.read_csv('https://raw.githubusercontent.com/farhanage/dataset-for-study/main/pokemon_data.csv')
df 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.
- Data bernilai
NaN
(Not a Number) - Data bernilai
0
(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.
= pd.DataFrame({"Evan" : [np.nan,100,95,94,99],"Boy" : [100,np.nan,95,99,94],"Maxwell" : [95,100,99,np.nan,94]})
df 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.
sum() df.isna().
Evan 1
Boy 1
Maxwell 1
dtype: int64
.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.
'Evan'].isna()] # Entri yang memiliki nilai `NaN` pada kolom `Evan` df[df[
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.
= pd.DataFrame({
df "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.
sum() df.duplicated().
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.
'id'].duplicated()] # Entri yang memiliki nilai `id` duplikat df[df[
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.
= pd.read_csv('https://raw.githubusercontent.com/farhanage/dataset-for-study/main/pokemon_data.csv')
df 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
='<value>', inplace=True) df.fillna(value
Menghapus data duplikat
=True) df.drop_duplicates(inplace