Data Manipulation With Pandas (part I)

Gifa Delyani Nursyafitri
22 min readNov 14, 2020

--

Source : https://www.fellow-consulting.com/data-analysis-with-pandas/

Holaaa people!

Weekend produktif kali ini kita akan ngelanjutin buat ngerjain rangkaian modul dari DQLab Career Track, yaitu Data Manipulation With Pandas.

Check it out!

Apa sih Pandas itu?

Pandas adalah library python open source yang biasanya digunakan untuk kebutuhan data analisis. Pandas membuat Python supaya dapat bekerja dengan data yang berbentuk tabular seperti spreadsheet dengan cara pemuatan data yang cepat, manipulasi data, menggabungkan data, serta ada berbagai fungsi yang lain.

Memanggil Library Pandas

Untuk memanggil library pandas cukup dengan meng-import nya, biasanya ketika memanggil library pandas, library numpy juga akan ikut dipanggil sehingga syntax nya menjadi seperti ini,

import pandas as pd
import numpy as np

DataFrame & Series

Ternyata dalam Pandas terdapat 2 kelas data baru yang digunakan sebagai struktur dari spreadsheet,

  1. Series: satu kolom bagian dari tabel dataframe yang merupakan 1 dimensional numpy array sebagai basis data nya, terdiri dari 1 tipe data (integer, string, float, dll).
  2. DataFrame: gabungan dari Series, berbentuk rectangular data yang merupakan tabel spreadsheet itu sendiri (karena dibentuk dari banyak Series, tiap Series biasanya punya 1 tipe data, yang artinya 1 dataframe bisa memiliki banyak tipe data).

Untuk lebih jelasnya, kita praktek aja ya.

import pandas as pd
# Series
number_list = pd.Series([1,2,3,4,5,6])
print("Series:")
print(number_list)
# DataFrame
matrix = [[1,2,3],
['a', 'b', 'c'],
[3,4,5],
['d', 4, 6]]
matrix_list = pd.DataFrame(matrix)
print("DataFrame:")
print(matrix_list)

Hasilnya adalah sebagai berikut,

Atribut DataFrame & Series

Dataframe dan Series ini juga memiliki sangat banyak atribut yang digunakan untuk transformasi data, tetapi hanya beberapa attribute yang sering digunakan.

Misalkan kita menggunakan data yang sama, kemudian akan kita praktekkan penggunaan atrribut

import pandas as pd
# Series
number_list = pd.Series([1,2,3,4,5,6])
# DataFrame
matrix_list = pd.DataFrame([[1,2,3],
['a','b','c'],
[3,4,5],
['d',4,6]])

1. Attribute.info()

Attribute.info() digunakan untuk mengecek kolom apa yang membentuk dataframe itu, data types, berapa yang non null, dll. Attribute ini tidak dapat digunakan pada series, hanya pada data frame saja.

# [1] attribute .info()
print("[1] attribute .info()")
print(matrix_list.info())

Outputnya akan seperti berikut ini,

2. Attribute .shape

Attribute.shape digunakan untuk mengetahui berapa baris dan kolom, hasilnya dalam format tuple (baris, kolom).

# [2] attribute .shape
print("\n[2] attribute .shape")
print(" Shape dari number_list:", number_list.shape)
print(" Shape dari matrix_list:", matrix_list.shape)

Output yang didapatkan adalah:

3. Attribute .dtypes

Attribute .dtypes digunakan untuk mengetahui tipe data di tiap kolom. Tipe data object: kombinasi untuk berbagai tipe data (number & text, etc).

# [3] attribute .dtypes
print("\n[3] attribute .dtypes")
print(" Tipe data number_list:", number_list.dtypes)
print(" Tipe data matrix_list:", matrix_list.dtypes)

Output yang dihasilkan adalah

4. Attribute .astype(nama_tipe_data)

Attribute .astype(nama_tipe_data) untuk convert tipe data berdasarkan tipe data seperti: float, int, str, numpy.float, numpy.int ataupun numpy.datetime.

# [4] attribute .astype()
print("\n[4] attribute .astype()")
print(" Konversi number_list ke str:", number_list.astype("str"))
print(" Konversi matrix_list ke str:", matrix_list.astype("str"))

Outputnya adalah

5. Attribute .copy()

Attribute .copy() digunakan melakukan duplikat, untuk disimpan di variable yang berbeda mungkin supaya tidak loading data lagi.

# [5] attribute .copy()
print("[5] attribute .copy()")
num_list = number_list.copy()
print(" Copy number_list ke num_list:", num_list)
mtr_list = matrix_list.copy()
print(" Copy matrix_list ke mtr_list:", mtr_list)

Output yang didapatkan adalah

6. Attribute .to_list()

Attribute .to_list() digunakan untuk mengubah series menjadi list dan tidak dapat digunakan untuk dataframe.

# [6] attribute .to_list()
print("[6] attribute .to_list()")
print(number_list.to_list())

Output yang dihasilkan adalah

7. Attribute .unique()

Attribute .unique() digunakan menghasilkan nilai unik dari suatu kolom, hasilnya dalam bentuk numpy array. Attribute ini hanya digunakan pada series saja.

# [7] attribute .unique()
print("[7] attribute .unique()")
print(number_list.unique())

8. Attribute .index

Attribute .index digunakan untuk mencari index/key dari Series atau Dataframe.

# [8] attribute .index
print("[8] attribute .index")
print(" Index number_list:", number_list.index)
print(" Index matrix_list:", matrix_list.index)

Output yang dihasilkan adalah

9. Attribute .columns

Attribute .columns digunakan untuk mengetahui apa saja kolom yang tersedia di dataframe tersebut (hanya digunakan untuk dataframe saja).

# [9] attribute .columns
print("[9] attribute .columns")
print(" Column matrix_list:", matrix_list.columns)

Dan output yang dihasilkan adalah

10. Attribute .loc

Attribute .loc digunakan slice dataframe atau series berdasarkan nama kolom dan/atau nama index.

# [10] attribute .loc
print("[10] attribute .loc")
print(" .loc[0:1] pada number_list:", number_list.loc[0:1])
print(" .loc[0:1] pada matrix_list:", matrix_list.loc[0:1])

Hasilnya akan seperti ini,

11. Attribute .iloc

Attribute .iloc digunakan untuk slice dataframe atau series berdasarkan index kolom dan/atau index.

# [11] attribute .iloc
print("[11] attribute .iloc")
print(" iloc[0:1] pada number_list:", number_list.iloc[0:1])
print(" iloc[0:1] pada matrix_list:", matrix_list.iloc[0:1])

Creating Series & Dataframe from List

Untuk membuat Series atau Dataframe bisa dari berbagai macam tipe data container/mapping di python, seperti list dan dictionary, maupun dari numpy array.

Kita akan mencoba untuk membuat Series dan Dataframe yang bersumber dari list. List merupakan sebuah kumpulan data dari berbagai macam tipe data, yang bersifat mutable (dapat diganti).

import pandas as pd
# Creating series from list
ex_list = ['a',1,3,5,'c','d']
ex_series = pd.Series(ex_list)
print(ex_series)
# Creating dataframe from list of list
ex_list_of_list = [[1, 'a', 'b', 'c'],
[2.5, 'd','e','f'],
[5, 'g', 'h', 'i'],
[7.5,'j',10.5,'l']]
index = ['dq','lab','kar','lan']
cols = ['float','char','obj','char']
ex_df = pd.DataFrame(ex_list_of_list, index=index, columns=cols)
print(ex_df)

Outpunya adalah sebagai berikut,

Creating Series & Dataframe from Dictionary

Selanjutnya kita akan membuat Series dan Dataframe yang bersumber dari dictionary. Dictionary sendiri merupakan kumpulan data yang strukturnya terdiri dari key dan value.

import pandas as pd
# Creating series from dictionary
dict_series = {'1': 'a',
'2': 'b',
'3': 'c'}
ex_series = pd.Series(dict_series)
print(ex_series)
# Creating dataframe from dictionary
df_series = {'1': ['a','b','c'],
'2': ['b','c','d'],
'4': [2,3,'z']}
ex_df = pd.DataFrame(df_series)
print(ex_df)

Hasilnya adalah

Creating Series & Dataframe from Numpy Array

Kemudian kita akan belajar membuat Series dan Dataframe yang bersumber dari numpy array. Numpy array disini merupakan kumpulan data yang terdiri atas berbagai macam tipe data, mutable, tapi dibungkus dalam array oleh library Numpy.

import pandas as pd
import numpy as np
# Creating series from numpy array (1D)
arr_series = np.array([1,2,3,4,5,6,6,7])
ex_series = pd.Series(arr_series)
print(ex_series)
# Creating dataframe from numpy array (2D)
arr_df = np.array([[1 ,2 ,3 ,5],
[5 ,6 ,7 ,8],
['a','b','c',10]])
ex_df = pd.DataFrame(arr_df)
print(ex_df)

Output yang dihasilkan adalah sebagai berkut,

Dataset I/O

Read Dataset — CSV dan TSV

CSV dan TSV pada dasarnya adalah tipe data text yang hampir sama dengan perbedaan terletak pada pemisah antar data dalam satu baris. Pada file CSV, antar data dalam satu baris dipisahkan oleh comma, “,” sedangkan pada file TSV antar data dalam satu baris dipisahkan oleh “Tab”.

Fungsi .read_csv() digunakan untuk membaca file yang value nya dipisahkan oleh comma (default), terkadang pemisah value nya bisa di set ‘\t’ untuk file tsv (tab separated values).

Datasetnya dapat di unduh disini :
1. Dataset csv

2. Dataset tsv

import pandas as pd
# File CSV
df_csv = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_csv.csv")
print(df_csv.head(3)) # Menampilkan 3 data teratas
# File TSV
df_tsv = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_tsv.tsv", sep='\t')
print(df_tsv.head(3)) # Menampilkan 3 data teratas

Output yang didapat adalah

Read Dataset — Excel

File Excel dengan ekstensi *.xls atau *.xlsx cukup banyak digunakan dalam menyimpan data. Pandas juga memiliki fitur untuk membaca file excel.

Dataset bisa diunduh di sini: Dataset Excel

Fungsi .read_excel() digunakan untuk membaca file excel menjadi dataframe pandas.

import pandas as pd
# File xlsx dengan data di sheet "test"
df_excel = pd.read_excel(" https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_excel.xlsx", sheet_name="test")
print(df_excel.head(4)) # Menampilkan 4 data teratas

Hasilnya adalah

Read Dataset — JSON

Method .read_json() digunakan untuk membaca URL API yang formatnya JSON dan merubahnya menjadi dataframe pandas. Dataset yang digunakan adalah Dataset Json.

import pandas as pd
# File JSON
url = "https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/covid2019-api-herokuapp-v2.json"
df_json = pd.read_json(url)
print(df_json.head(10)) # Menampilkan 10 data teratas

Outputnya adalah

Read Dataset — SQL

Fungsi .read_sql() atau .read_sql_query() digunakan untuk membaca query dari database dan translate menjadi pandas dataframe, contoh case ini database sqlite.

Jika menggunakan .read_sql_query

Dan outputnya adalah

Jika menggunakan .read_sql

Output yang dihasilkan adalah

Terlihat keduanya menghasilkan output yang sama.

Read Dataset — Google BigQuery

Untuk data yang besar (big data), umumnya digunakan Google BigQuery. Layanan ini dapat digunakan jika telah memiliki Google BigQuery account.

Fungsi .read_gbq() digunakan untuk membaca Google BigQuery table menjadi dataframe pandas.

project_id=”XXXXXXXX” adalah ID dari Google BigQuery account yang digunakan. Output yang dihasilkan seperti ini,

Write Dataset

Ketika kita bekerja sebagai data scientist atau data analyst, maka kita perlu menyimpan data yang telah melalui proses cleansing ke dalam media penyimpanan. Menariknya, ternyata Pandas menyediakan fitur demikian secara ringkas melalui penerapan method pada dataframe/series yang ditabelkan berikut ini.

Head & Tail

Seperti yang telah dipelajari sebelumnya bahwa ada method .head yang diterapkan pada suatu variabel bertipe pandas baik itu dataframe atau series.

Method .head bertujuan untuk membatasi tampilan jumlah baris teratas dari dataset. Sementara itu, method .tail digunakan untuk membatasi jumlah baris terbawah dari dataset.

Secara umum kedua method ini memiliki bentuk

[nama_dataframe].head(n)
[nama_dataframe].tail(n)

dengan n merupakan jumlah baris yang akan ditampilkan, jika tidak disebutkan n = 5 (sebagai nilai default dari n).

import pandas as pd
# Baca file sample_csv.csv
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_csv.csv")
# Tampilkan 3 data teratas
print("Tiga data teratas:\n", df.head(3))
# Tampilkan 3 data terbawah
print("Tiga data terbawah:\n", df.tail(3))

Indexing, Slicing, dan Transforming

Indexing

Index merupakan key identifier dari tiap row/column untuk Series atau Dataframe (sifatnya tidak mutable untuk masing-masing value tapi bisa diganti untuk semua value sekaligus).

Jika tidak disediakan, pandas akan membuat kolom index default secara otomatis sebagai bilangan bulat (integer) dari 0 sampai range jumlah baris data tersebut.

Kolom index dapat terdiri dari:

  1. satu kolom (single index), atau
  2. multiple kolom (disebut dengan hierarchical indexing).

Index dengan multiple kolom ini terjadi karena unique identifier tidak dapat dicapai hanya dengan set index di 1 kolom saja sehingga membutuhkan beberapa kolom yang menjadikan tiap row menjadi unique.

Secara default setelah suatu data frame dibaca dari file dengan format tertentu, index-nya merupakan single index.

Untuk menentukan index dan kolom yang dimiliki oleh dataset yang berbentuk dataframe, maka dapat dilakukan dengan menggunakan attribut .index dan .columns. Nah, kita coba yuk untuk mencetak index dan kolom yang dimiliki oleh file “sample_csv.csv”.

import pandas as pd
# Baca file TSV sample_tsv.tsv
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_tsv.tsv", sep="\t")
# Index dari df
print("Index:", df.index)
# Column dari df
print("Column:", df.columns)

Jika syntax berhasil dijalankan maka akan menghasilkan output:

Selanjutnya kita akan mempelajari tentang multi index atau disebut juga dengan hierarchical indexing.

Untuk membuat multi index (hierarchical indexing) dengan pandas diperlukan kolom-kolom mana saja yang perlu disusun agar index dari data frame menjadi sebuah hirarki yang kemudian dapat dikenali.

Kita akan membuat multi index dengan menggunakan kolom ‘order_id’, ‘customer_id’, ‘product_id’, dan ‘order_date’ dengan menggunakan method .set_index().

import pandas as pd
# Baca file TSV sample_tsv.tsv
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_tsv.tsv", sep="\t")
# Set multi index df
df_x = df.set_index(['order_date', 'city', 'customer_id'])
# Print nama dan level dari multi index
for name, level in zip(df_x.index.names, df_x.index.levels):
print(name,':',level)

Hasilnya adalah

Kumpulan index yang ada di multi index adalah list dari banyak tuples, tuples nya merupakan kombinasi yang ada dari gabungan index-index tersebut. Dari multi index tersebut juga terdapat atribut levels yang menunjukkan urutan index, dalam case ini ‘order_id’ > ‘customer_id’ > ‘product_id’ > ‘order_date’.

Selanjutnya kita akan belajar menggunakan assignment untuk menset index dari suatu data frame.

import pandas as pd
# Baca file sample_tsv.tsv untuk 10 baris pertama saja
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_tsv.tsv", sep="\t", nrows=10)
# Cetak data frame awal
print("Dataframe awal:\n", df)
# Set index baru
df.index = ["Pesanan ke-" + str(i) for i in range(1, 11)]
# Cetak data frame dengan index baru
print("Dataframe dengan index baru:\n", df)

Misalkan file yang akan dibaca dapat dipreview terlebih dahulu struktur datanya, maka kita dapat melakukan set di kolom mana yang akan dijadikan index.

Fitur ini telah dimiliki oleh setiap fungsi yang digunakan dalam membaca data dengan pandas, yaitu penggunaan argumen index_col pada fungsi yang dimaksud. Untuk jelasnya dapat diperhatikan pada kode berikut ini.

import pandas as pd
# Baca file sample_tsv.tsv dan set lah index_col sesuai instruksi
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_tsv.tsv", sep="\t", index_col=["order_date", "order_id"])
# Cetak data frame untuk 8 data teratas
print("Dataframe:\n", df.head(8))

Jika berhasil dijalankan kodenya maka akan tampil hasil berikut:

Slicing

Slicing merupakan cara untuk melakukan filter ke dataframe/series berdasarkan kriteria tertentu dari nilai kolomnya ataupun kriteria index-nya.

Terdapat 2 cara paling terkenal untuk slicing dataframe, yaitu dengan menggunakan method .loc dan .iloc pada variabel bertipe pandas DataFrame/Series. Method .iloc ditujukan untuk proses slicing berdasarkan index berupa nilai integer tertentu. Akan tetapi akan lebih sering menggunakan dengan method .loc karena lebih fleksibel.

import pandas as pd
# Baca file sample_csv.csv
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_csv.csv")
# Slice langsung berdasarkan kolom
df_slice = df.loc[(df["customer_id"] == "18055") &
(df["product_id"].isin(["P0029","P0040","P0041","P0116","P0117"]))
]
print("Slice langsung berdasarkan kolom:\n", df_slice)

Selanjutnya kita akan menerapkan slicing berdasarkan index. Tentu syaratnya adalah dataset sudah dilakukan indexing terlebih dahulu melalui penerapan method .set_index

import pandas as pd
# Baca file sample_csv.csv
df = pd.read_csv ("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_csv.csv")
# Set index dari df sesuai instruksi
df = df.set_index(["order_date", "order_id", "product_id"])
# Slice sesuai intruksi
df_slice = df.loc[("2019-01-01",1612339,["P2154","P2159"]),:]
print("Slice df:\n", df_slice)

Transforming

Transform adalah ketika mengubah dataset yang ada menjadi entitas baru, dapat dilakukan dengan

  • konversi dari satu data type ke data type yang lain,
  • transpose dataframe
  • atau yang lainnya.

Hal yang biasa dilakukan pertama kali setelah data dibaca adalah mengecek tipe data di setiap kolomnya apakah sesuai dengan representasinya. Untuk itu dapat menggunakan attribut .dtypes pada dataframe yang telah kita baca tadi,

[nama_dataframe].dtypes

Untuk konversi tipe data, secara default system akan mendeteksi data yang tidak bisa di render as date type or numeric type sebagai object yang basically string. Tidak bisa di render oleh system ini karena berbagai hal, mungkin karena formatnya asing dan tidak dikenali oleh python secara umum (misal: date type data → ‘2019Jan01’).

Data contoh tersebut tidak bisa di render karena bulannya Jan tidak bisa di translate menjadi in form of number (00–12) dan tidak ada ‘-’ di antara tahun, bulan dan harinya. Jika seluruh data pada kolom di order_date sudah tertulis dalam bentuk ‘YYYY-MM-DD’ maka ketika dibaca, kolom order_date sudah langsung dinyatakan bertipe data datetime.

Untuk merubah kolom date_order yang sebelumnya bertipe object menjadi kolom bertipe datetime, cara pertama yang dapat dilakukan adalah menggunakan

pd.to_datetime(argumen)

dengan argumen adalah isi kolom dari dataframe yang akan dirubah tipe datanya, misal dalam format umum

nama_dataframe["nama_kolom"]

Sehingga lengkapnya dapat ditulis sebagai

nama_dataframe["nama_kolom"] = pd.to_datetime(nama_dataframe["nama_kolom"])

Agar lebih paham, kita bisa mencoba dengan cara berikut:

import pandas as pd
# Baca file sample_csv.csv
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_csv.csv")
# Tampilkan tipe data
print("Tipe data df:\n", df.dtypes)
# Ubah tipe data kolom order_date menjadi datetime
df["order_date"] = pd.to_datetime(df["order_date"])
# Tampilkan tipe data df setelah transformasi
print("\nTipe data df setelah transformasi:\n", df.dtypes)

Outputnya adalah

Kemudian kita akan belajar mengubah tipe data pada kolom dataframe yang sama menjadi tipe data float (kolom quantity) dan tipe categori (kolom city).

Secara umum, untuk merubah ke numerik dapat menggunakan pd.to_numeric(), yaitu

nama_dataframe["nama_kolom"] = pd.to_numeric(nama_dataframe["nama_kolom"], downcast="tipe_data_baru")

Sedangkan untuk menjadi suatu kolom yang dapat dinyatakan sebagai kategory dapat menggunakan method .astype() pada dataframe, yaitu

nama_dataframe["nama_kolom"] = nama_dataframe["nama_kolom"].astype("category")

Agar lebih jelasnya, yuk praktekin!

import pandas as pd
# Baca file sample_csv.csv
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_csv.csv")
# Tampilkan tipe data
print("Tipe data df:\n", df.dtypes)
# Ubah tipe data kolom quantity menjadi tipe data numerik float
df["quantity"] = pd.to_numeric(df["quantity"], downcast="float")
# Ubah tipe data kolom city menjadi tipe data category
df["city"] = df["city"].astype("category")
# Tampilkan tipe data df setelah transformasi
print("\nTipe data df setelah transformasi:\n", df.dtypes)

Outputnya adalah

Kita kemudian akan belajar menggunakan method .apply() dan .map() pada suatu dataframe.

Method .apply() digunakan untuk menerapkan suatu fungsi python (yang dibuat dengan def atau anonymous dengan lambda) pada dataframe/series atau hanya kolom tertentu dari dataframe.

Method .map() hanya dapat diterapkan pada series atau dataframe yang diakses satu kolom saja. Method ini digunakan untuk mensubstitusikan suatu nilai ke dalam tiap baris datanya.

Berikut ini adalah contohnya yaitu akan merubah setiap baris pada kolom brand menjadi lowercase.

import pandas as pd
# Baca file sample_csv.csv
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/sample_csv.csv")
# Cetak 5 baris teratas kolom brand
print("Kolom brand awal:\n", df["brand"].head())
# Gunakan method apply untuk merubah isi kolom menjadi lower case
df["brand"] = df["brand"].apply(lambda x: x.lower())
# Cetak 5 baris teratas kolom brand
print("Kolom brand setelah apply:\n", df["brand"].head())
# Gunakan method map untuk mengambil kode brand yaitu karakter terakhirnya
df["brand"] = df["brand"].map(lambda x: x[-1])
# Cetak 5 baris teratas kolom brand
print("Kolom brand setelah map:\n", df["brand"].head())

Outputnya

Selanjutnya kita akan menggunakan method .applymap pada dataframe.

import numpy as np
import pandas as pd
# number generator, set angka seed menjadi suatu angka, bisa semua angka, supaya hasil random nya selalu sama ketika kita run
np.random.seed(1234)
# create dataframe 3 baris dan 4 kolom dengan angka random
df_tr = pd.DataFrame(np.random.rand(3,4))
# Cetak dataframe
print("Dataframe:\n", df_tr)
# Cara 1 dengan tanpa define function awalnya, langsung pake fungsi anonymous lambda x
df_tr1 = df_tr.applymap(lambda x: x**2 + 3*x + 2)
print("\nDataframe - cara 1:\n", df_tr1)
# Cara 2 dengan define function
def qudratic_fun(x):
return x**2 + 3*x + 2
df_tr2 = df_tr.applymap(qudratic_fun)
print("\nDataframe - cara 2:\n", df_tr2)

Output yang dihasilkan adalah

Handling Missing Values

Inspeksi Missing Value

Value yang hilang serta tidak lengkap dari dataframe akan membuat analisis atau model prediksi yang dibuat menjadi tidak akurat dan mengakibatkan keputusan salah yang diambil. Terdapat beberapa cara untuk mengatasi data yang hilang/tidak lengkap tersebut.

Kali ini, kita akan menggunkan Data COVID-19 yang diambil dari google big query, tetapi sudah disediakan datasetnya dalam format csv dengan nama “public data covid19 jhu csse eu.csv”. Untuk mengakses datanya bisa klik di sini. Ini adalah studi kasus untuk meng-handle missing value. Bagaimanakah langkah-langkahnya?

Di pandas data yang hilang umumnya direpresentasikan dengan NaN.

Langkah pertama, harus tahu kolom mana yang terdapat data hilang dan berapa banyak dengan cara:

Cara 1: menerapkan method .info() pada dataframe yang dapat diikuti dari kode berikut ini

Cara 2: mengetahui berapa banyak nilai hilang dari tiap kolom di dataset tersebut dengan menerapkan chaining method pada dataframe yaitu .isna().sum().

import pandas as pd
# Baca file "public data covid19 jhu csse eu.csv"
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/CHAPTER+4+-+missing+value+-+public+data+covid19+.csv")
# Cetak info dari df
print(df.info())
# Cetak jumlah missing value di setiap kolom
mv=df.isna().sum()
print("\nJumlah missing value per kolom:\n", mv)

Output dari cara 1 :

Output dari cara 2:

Treatment untuk Missing Value

Terdapat beberapa cara untuk mengatasi missing value, antara lain:

  1. Biarkan saja,
  2. Menghapus value tsb, atau
  3. Mengganti value tersebut dengan value yang lain (biasanya interpolasi, mean, median, etc)

Sebelum melakukan action ke missing value pada data covid diatas, sebaiknya tampilkan beberapa row teratas dari dataset tersebut,

dan dilihat kembali jumlah missing value tiap kolomnya agar dapat ditelaah terlebih dahulu.

Hanya kolom combine_key yang keseluruhan barisnya adalah missing value (1000 buah), sementara kolom country_region, date, dan confirmed tidak memiliki missing value. Untuk kolom lainnya terdapat beragam jumlah missing value. Apa yang dapat dilakukan?

Untuk memahami mana kolom yang akan ditreatment dengan tiga perlakukan di atas lihat nature dari data terlebih dahulu. Contohnya pada kolom death dan recovered jika ada yang missing value maka kemungkinan terbesarnya adalah tidak ada meninggal atau sembuh pada hari tersebut.

Untuk kolom yang seluruhnya missing yaitu combined_key dapat dibuang saja satu kolom itu karena tidak ada data yang dapat diketahui dari kolom tersebut.

Sementara, kolom yang lainnya bagaimana? Misal ambil kolom province_stat, missing valuenya dapat terjadi bahwa tidak dilaporkan itu berasal dari daerah mana di negara itu. Dapat mengisi misal dengan string ‘unknown’ karena tahu kolom tersebut bertipe data string.

Sekarang dapat menerapkan dua aksi yaitu

  1. Membiarkannya saja

Treatment pertama (membiarkannya saja) seperti pada kolom confirmed, death, dan recovered. Akan tetapi jika tidak ada yang terkonfirmasi, meninggal dan sembuh sebenarnya dapat menukar value ini dengan angka nol. Meskipun ini lebih make sense dalam representasi datanya, tetapi untuk sub bab ini ketiga kolom tersebut diasumsikan dibiarkan memiliki nilai missing value.

2. Menghapus Kolom

Treatment kedua yaitu dengan menghapus kolom, yang mana ini digunakan jika seluruh kolom dari dataset yang dipunyai semua barisnya adalah missing value. Untuk itu dapat menerapkan method .dropna() pada dataframe, bagaimana caranya?

nama_dataframe.dropna(axis=1, how="all")

Pada method .dropna() ada dua keyword argumen yang harus diisikan yaitu axis dan how. Keyword axis digunakan untuk menentukan arah dataframe yang akan dibuang angka 1 untuk menyatakan kolom (column-based) atau dapat ditulis dalam string “column”. Jika digunakan angka 0 berarti itu dalam searah index (row-based) atau dapat ditulis dalam string “index”.

Sementara, keyword how digunakan untuk bagaimana cara membuangnya. Opsi yang dapat diterimanya (dalam string) adalah

  • “all” artinya jika seluruh data di satu/beberapa kolom atau di satu/beberapa baris adalah missing value.
  • “any” artinya jika memiliki 1 saja data yang hilang maka buanglah baris/kolom tersebut.
import pandas as pd
# Baca file "public data covid19 jhu csse eu.csv"
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/CHAPTER+4+-+missing+value+-+public+data+covid19+.csv")
# Cetak ukuran awal dataframe
print("Ukuran awal df: %d baris, %d kolom." % df.shape)
# Drop kolom yang seluruhnya missing value dan cetak ukurannya
df = df.dropna(axis=1, how="all")
print("Ukuran df setelah buang kolom dengan seluruh data missing: %d baris, %d kolom." % df.shape)
# Drop baris jika ada satu saja data yang missing dan cetak ukurannya
df = df.dropna(axis=0, how="any")
print("Ukuran df setelah dibuang baris yang memiliki sekurangnya 1 missing value: %d baris, %d kolom." % df.shape)

3. Mengisi Missing Value dengan Nilai Lain

Sekarang, kita akan melakukan treatment ketiga untuk menghandle missing value pada dataframe. Treatment ini dilakukan dengan cara mengisi missing value dengan nilai lain, yang dapat berupa :

  • nilai statistik seperti mean atau median
  • interpolasi data
  • text tertentu

Akan mulai pada kolom yang missing yang tipe datanya adalah berupa object. Kolom tersebut adalah province_state, karena tidak tahu secara persis province_state mana yang dimaksud, bisa menempatkan string “unknown” sebagai substitusi missing value. Meskipun keduanya berarti sama-sama tidak tahu tetapi berbeda dalam representasi datanya.

Untuk melakukan hal demikian dapat menggunakan method .fillna() pada kolom dataframe yang dimaksud.

import pandas as pd
# Baca file "public data covid19 jhu csse eu.csv"
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/CHAPTER+4+-+missing+value+-+public+data+covid19+.csv")
# Cetak unique value pada kolom province_state
print("Unique value awal:\n", df["province_state"].unique())
# Ganti missing value dengan string "unknown_province_state"
df["province_state"] = df["province_state"].fillna("unknown_province_state")
# Cetak kembali unique value pada kolom province_state
print("Unique value setelah fillna:\n", df["province_state"].unique())

Selanjutnya kita akan mengganti missing value dengan nilai statistik kolom bersangkutan, baik median atau mean (nilai rata-rata). Misalnya akan menggunakan kolom active. Dengan mengabaikan terlebih dahulu sebaran berdasarkan negara (univariate), jika mengisi dengan nilai rata-rata maka harus melihat terlebih dahulu data apakah memiliki ouliers atau tidak. Jika ada outliers dari data maka menggunakan nilai tengah (median) data adalah cara yang lebih safe.

Untuk itu diputuskan dengan mengecek nilai median dan nilai mean kolom active juga nilai min dan max-nya. Jika data pada kolom active terdistribusi normal maka nilai mean dan median akan hampir sama.

Terlihat data memiliki distribusi yang skewness, karena nilai mean dan median yang cukup jauh serta range data yang cukup lebar. Di sini pada kolom active data memiliki outliers. Jadi akan mengisi missing value dengan median.

import pandas as pd
# Baca file "public data covid19 jhu csse eu.csv"
df = pd.read_csv("https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/CHAPTER+4+-+missing+value+-+public+data+covid19+.csv")
# Cetak nilai mean dan median awal
print("Awal: mean = %f, median = %f." % (df["active"].mean(), df["active"].median()))
# Isi missing value kolom active dengan median
df_median = df["active"].fillna(df["active"].median())
# Cetak nilai mean dan median awal setelah diisi dengan median
print("Fillna median: mean = %f, median = %f." % (df_median.mean(), df_median.median()))
# Isi missing value kolom active dengan mean
df_mean = df["active"].fillna(df["active"].mean())
# Cetak nilai mean dan median awal setelah diisi dengan mean
print("Fillna mean: mean = %f, median = %f." % (df_mean.mean(), df_mean.median()))

Outputnya adalah :

Di bagian ini akan menggunakan teknik interpolasi dalam mengisi nilai missing value pada suatu dataset.

Data yang menggunakan interpolasi untuk mengisi data yang hilang adalah time series data, yang secara default akan diisi dengan interpolasi linear.

import numpy as np
import pandas as pd
# Data
ts = pd.Series({
"2020-01-01":9,
"2020-01-02":np.nan,
"2020-01-05":np.nan,
"2020-01-07":24,
"2020-01-10":np.nan,
"2020-01-12":np.nan,
"2020-01-15":33,
"2020-01-17":np.nan,
"2020-01-16":40,
"2020-01-20":45,
"2020-01-22":52,
"2020-01-25":75,
"2020-01-28":np.nan,
"2020-01-30":np.nan
})
# Isi missing value menggunakan interpolasi linier
ts = ts.interpolate()
# Cetak time series setelah interpolasi linier
print("Setelah diisi missing valuenya:\n", ts)

Sehingga outputnya adalah :

Mini Project

Untuk melihat tingkat pemahaman kita, kita akan mencoba mengerjakan project untuk melakukan ETL di data untuk cabang perusahaan ritel. Data tersebut merupakan kumpulan data bulan Januari 2019 untuk setiap kota dan provinsi, tanggal ordernya, customer, ordernya apa aja terkait brand, product, quantity dan item pricenya juga. Dan, yang terakhir adalah GMV/Gross Merchandise Volume (total price)-nya.

Diberikan dataset retail_raw_test.csv

  1. Baca dataset

Karena data yang dimiliki berbentuk csv, maka kita dapat

# 1. Baca dataset
print("[1] BACA DATASET")
df = pd.read_csv(" https://dqlab-dataset.s3-ap-southeast-1.amazonaws.com/retail_raw_test.csv", low_memory=False)
print(" Dataset:\n", df.head())
print(" Info:\n", df.info())

Hasilnya adalah sebagai berikut.

2. Tipe data diubah menjadi tipe yang seharusnya

  • customer_id dari string ke int64,
  • quantity dari string ke int64,
  • item_price dari string ke int64
# 2. Ubah tipe data
print("\n[2] UBAH TIPE DATA")
df["customer_id"] = df["customer_id"].apply(lambda x: x.split("'")[1]).astype("int64")
df["quantity"] = df["quantity"].apply(lambda x: x.split("'")[1]).astype("int64")
df["item_price"] = df["item_price"].apply(lambda x: x.split("'")[1]).astype("int64")
print(" Tipe data:\n", df.dtypes)

Dapat dilihat bahwa tipe kolom customer_id, quantity, serta item_price telah berubah menjadi int64.

3. Transform product_value supaya bentuknya seragam dengan format PXXXX, assign ke kolom baru “product_id”, dan drop kolom “product_value”, jika terdapat nan gantilah dengan “unknown”.

# 3. Transform "product_value" supaya bentuknya seragam dengan format "PXXXX", assign ke kolom baru "product_id", dan drop kolom "product_value", jika terdapat nan gantilah dengan "unknown"
print("\n[3] TRANSFORM product_value MENJADI product_id")
# Buat fungsi
import math
def impute_product_value(val):
if math.isnan(val):
return "unknown"
else:
return 'P' + '{:0>4}'.format(str(val).split('.')[0])
# Buat kolom "product_id"
df["product_id"] = df["product_value"].apply(lambda x: impute_product_value(x))
# Hapus kolom "product_value"
df.drop(["product_value"], axis=1, inplace=True)
# Cetak 5 data teratas
print(df.head())

Berdasarkan output yang dihasilkan, product_value sudah tidak tersedia lagi dan format untuk product_id sudah terlihat lebih rapi.

4. Tranform order_date menjadi value dengan format YYYY-mm-dd

Karena format pada order_date bukan merupakan format date pada pandas, maka kita perlu mentransformasi terlebih dahulu menggunakan dictionary. Selain itu kita juga menambahkan tanda (-) diantara hari, bulan, dan tahun.

# 4. Tranform order_date menjadi value dengan format "YYYY-mm-dd"
print("\n[4] TRANSFORM order_date MENJADI FORMAT YYYY-mm-dd")
months_dict = {
"Jan":"01",
"Feb":"02",
"Mar":"03",
"Apr":"04",
"May":"05",
"Jun":"06",
"Jul":"07",
"Aug":"08",
"Sep":"09",
"Oct":"10",
"Nov":"11",
"Dec":"12"
}
df["order_date"] = pd.to_datetime(df["order_date"].apply(lambda x: str(x)[-4:] + "-" + months_dict[str(x)[:3]] + "-" + str(x)[4:7]))
print(" Tipe data:\n", df.dtypes)

Dari output yang dihasilkan, kita dapat melihat bahwa order_date telah bertipe datetime64[ns].

5. cek data hilang dari tiap kolom dan kemudian isi missing value

  • di brand dengan “no_brand”, dan
  • cek dulu bagaimana missing value di city & province — isi missing value di city dan province dengan “unknown”
# 5. Mengatasi data yang hilang di beberapa kolom
print("\n[5] HANDLING MISSING VALUE")
# Kolom "city" dan "province" masih memiliki missing value, nilai yang hilang di kedua kolom ini diisi saja dengan "unknown"
df[["city","province"]] = df[["city","province"]].fillna("unknown")
# Kolom brand juga masih memiliki missing value, Ganti value NaN menjadi "no_brand"
df["brand"] = df["brand"].fillna("no_brand")
# Cek apakah masih terdapat missing value di seluruh kolom
print(" Info:\n", df.info())

Hore! Dari output ini kita bisa lihat kalo missing value nya udah hilang termasuk di brand juga city dan province.

6. Create column city/province dari gabungan city & province

Agar lebih mudah, maka kita akan menggabungkan antara city dan province, tapi setelah itu field city dan province nya juga di hapus ya biar efektif.

# 6. Membuat kolom baru "city/province" dengan menggabungkan kolom "city" dan kolom "province" dan delete kolom asalnya
print("\n[6] MEMBUAT KOLOM BARU city/province")
df["city/province"] = df["city"] + "/" + df["province"]
# drop kolom "city" dan "province" karena telah digabungkan
df.drop(["city","province"], axis=1, inplace=True)
# Cetak 5 data teratas
print(df.head())

Nah, udah jadi nih. Sekarang kita punya 8 kolom loh, lebih ringkas dan efektif kan?

7. Membuat index berdasarkan city_provice, order_date, customer_id, order_id, product_id (cek index)

# 7. Membuat hierarchical index yang terdiri dari kolom "city/province", "order_date", "customer_id", "order_id", "product_id"
print("\n[7] MEMBUAT HIERACHICAL INDEX")
df = df.set_index(["city/province","order_date","customer_id","order_id","product_id"])
# urutkanlah berdasarkan index yang baru
df = df.sort_index()
# Cetak 5 data teratas
print(df.head())

Nah setelah berhasil, maka tampilannya akan seperti ini,

8. Membuat kolom “total_price” sebagai hasil perkalian quantity dengan item_price.

Agar informasi yang tersedia lebih lengkap dan lebih mempermudah proses analisa, maka kita perlu menambahkan field total_price.

# 8. Membuat kolom "total_price" yang formula nya perkalian antara kolom "quantity" dan kolom "item_price"
print("\n[8] MEMBUAT KOLOM total_price")
df["total_price"] = df["quantity"] * df["item_price"]
# Cetak 5 data teratas
print(df.head())

Taraaa, field total_price berhasil ditambah.

9. Slice data hanya untuk Jan 2019

Nah, misalkan kita hanya ingin melihat data untuk Januari 2019, maka kita perlu melakukan filter dengan slice.

# 9. Slice dataset agar hanya terdapat data bulan Januari 2019
print("\n[9] SLICE DATASET UNTUK BULAN JANUARI 2019 SAJA")
idx = pd.IndexSlice
df_jan2019 = df.loc[idx[:, "2019-01-01":"2019-01-31"], :]
print("Dataset akhir:\n", df_jan2019)

Dan akhirnya sampailah kita di tahap akhir. Data nya terlihat lebih rapi dan siap untuk diolah.

See you next week dengan pembahasan yang tak kalah menatangnya!

Reference:

DQLab Module : Data Manipulation With Pandas Part I

Mentor : Karl Christian (Business Intelligence Traveloka)

--

--

Gifa Delyani Nursyafitri
Gifa Delyani Nursyafitri

Written by Gifa Delyani Nursyafitri

Ku abadikan disini, karena aku paham betul bahwa ingatan manusia terbatas.

No responses yet