Pengolahan Data dengan Pandas

Pada chapter ini, kita akan belajar menggunakan module eksternal Pandas untuk melakukan pengolahan data. Untuk melakukan instalasi pandas, buka program CMD.exe Prompt lewat Anaconda Navigator, lalu jalankan perintah di bawah ini:

conda install pandas

Setelah itu, jalankan aplikasi Spyder dari Anaconda Navigator dan tulis kode di bawah ini untuk melakukan impor module Pandas:

import pandas as pd

Mengenal DataFrame

Pandas memiliki konsep DataFrame yang merepresentasikan sebuah data structure tabular atau data berbentuk tabel yang terdiri dari row dan column. Contoh di bawah ini memperlihatkan cara untuk membuat variable DataFrame:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

print(df)
# Output:
#                  name nationality  age
# 0  Christiano Ronaldo    Portugal   39
# 1        Lionel Messi   Argentina   36
# 2       Kylian Mbappé      France   25

Apabila dijalankan, variable df akan menyimpan DataFrame dengan 3 column (‘name’, ‘nationality’, dan ‘age’) dan 3 row.

Untuk mendapatkan semua nilai pada column tertentu, kita dapat menulis kode seperti contoh berikut:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

print(df['name'])
# Output:
# 0    Christiano Ronaldo
# 1          Lionel Messi
# 2         Kylian Mbappé
# Name: name, dtype: object

print(df['age'])
# Output:
# 0    39
# 1    36
# 2    25
# Name: age, dtype: int64

Apabila ingin melakukan seleksi pada beberapa column sekaligus, kita dapat mengikuti contoh di bawah ini:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

print(df[['name', 'age']])
# Output:
#                  name  age
# 0  Christiano Ronaldo   39
# 1        Lionel Messi   36
# 2       Kylian Mbappé   25

Setiap row pada DataFrame akan otomatis mendapatkan index, mulai dari index 0 sampai n-1 (n adalah jumlah baris pada DataFrame). Untuk mengakses data pada row tertentu, kita dapat menggunakan fungsi loc dan index seperti pada contoh berikut:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

print(df.loc[1])
# Output:
# name           Lionel Messi
# nationality       Argentina
# age                      36
# Name: 1, dtype: object

Untuk mendapatkan tepat satu nilai pada DataFrame dari posisi row dan column tertentu, kita dapat mengikuti contoh di bawah ini:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

print(df['age'][0])
# Output:
# 39

Pandas juga memiliki fungsi untuk membaca data dari file di komputer dengan format .csv. Hasil dari pembacaan data tersebut akan dikonversi menjadi DataFrame oleh Pandas.

# Parameter delimiter bisa diganti dengan karakter lain seperti ';' dsb.
df = pd.read_csv('data/contoh.csv', delimiter = ',')

Selain membaca dari file .csv di komputer, Pandas juga bisa membaca file .csv yang diakses dari internet. Cara penggunaannya seperti kode di bawah ini:

# Parameter berupa alamat URL yang aksesnya publik
df = pd.read_csv('https://raw.githubusercontent.com/pandas-dev/pandas/main/doc/data/titanic.csv', delimiter = ',')

Modifikasi nilai pada DataFrame

Kita bisa mengubah nilai pada DataFrame seperti halnya list dan dictionary. Di bawah ini adalah contoh modifikasi nilai dengan menggunakan nama column dan index row:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

df['age'][0] = df['age'][0] - 10

print(df)
# Output:
#                  name nationality  age
# 0  Christiano Ronaldo    Portugal   29
# 1        Lionel Messi   Argentina   36
# 2       Kylian Mbappé      France   25

Untuk mengganti beberapa nilai sekaligus pada satu row, kita bisa menggunakan fungsi loc seperti di bawah ini:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

df.loc[2] = ['Harry Kane', 'England', 30]

print(df)
# Output:
#                  name nationality  age
# 0  Christiano Ronaldo    Portugal   39
# 1        Lionel Messi   Argentina   36
# 2          Harry Kane     England   30

List baru yang kita set ke suatu row harus memiliki panjang yang sama dengan jumlah column. Apabila berbeda, Pandas akan mengeluarkan error seperti berikut:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

df.loc[2] = ['Harry Kane', 'England']
# Output:
# raise ValueError(
#   ValueError: Must have equal len keys and value when setting with an iterable

Kita juga bisa mengubah beberapa nilai pada satu column seperti berikut:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

df['age'] = [29, 29, 29]

print(df)
# Output:
#                  name nationality  age
# 0  Christiano Ronaldo    Portugal   29
# 1        Lionel Messi   Argentina   29
# 2       Kylian Mbappé      France   29

List baru yang kita set ke suatu column harus memiliki panjang yang sama dengan jumlah row. Apabila berbeda, Pandas akan mengeluarkan error seperti berikut:

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

df['age'] = [29, 29]
# Output:
# ...
# raise ValueError(
#  ValueError: Length of values (2) does not match length of index (3)

Untuk menambah column baru, kita bisa membuat key baru pada variable DataFrame, lalu set sebuah list menjadi nilai dari column tersebut. Pastikan panjang list sama dengan jumlah row pada DataFrame.

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

df['club'] = ['Al-Nassr FC', 'Inter Miami CF', 'Paris Saint-Germain F.C.']

print(df)
# Output:
#                  name nationality  age                      club
# 0  Christiano Ronaldo    Portugal   39               Al-Nassr FC
# 1        Lionel Messi   Argentina   36            Inter Miami CF
# 2       Kylian Mbappé      France   25  Paris Saint-Germain F.C.

Untuk menambah row baru, kita bisa membuat index row baru pada variable DataFrame, lalu set sebuah list menjadi nilai dari row tersebut. Pastikan panjang list sama dengan jumlah column pada DataFrame.

df = pd.DataFrame({
    'name': ['Christiano Ronaldo', 'Lionel Messi', 'Kylian Mbappé'],
    'nationality': ['Portugal', 'Argentina', 'France'],
    'age': [39, 36, 25]
})

df.loc[len(df)] = ['Harry Kane', 'England', 30]

print(df)
# Output:
#                  name nationality  age
# 0  Christiano Ronaldo    Portugal   39
# 1        Lionel Messi   Argentina   36
# 2       Kylian Mbappé      France   25
# 3          Harry Kane     England   30

Untuk mempelajari Pandas lebih lanjut, kita membutuhkan data yang lebih banyak. Data yang akan kita gunakan adalah data penumpang kapal Titanic yang dapat diunduh di sini. Setelah di unduh, copy file titanic.csv ke dalam folder/directory projek kamu. Buat file Python baru, lalu tulis kode berikut untuk membaca file:

import pandas as pd

df_titanic = pd.read_csv('titanic.csv', delimiter = ',')
print(df_titanic.head())
# Output:
#    PassengerId  Survived  Pclass  ...     Fare Cabin  Embarked
# 0            1         0       3  ...   7.2500   NaN         S
# 1            2         1       1  ...  71.2833   C85         C
# 2            3         1       3  ...   7.9250   NaN         S
# 3            4         1       1  ...  53.1000  C123         S
# 4            5         0       3  ...   8.0500   NaN         S
#
# [5 rows x 12 columns]

print(df_titanic.columns)
# Output:
# Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
#        'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'],
#       dtype='object')

Pada contoh, kita menggunakan fungsi head untuk melihat sampel data dari DataFrame dan property columns untuk mendapatkan informasi column apa saja yang ada di DataFrame.

Filtering dan sorting pada DataFrame

Karena DataFrame memiliki bentuk tabular, filtering dan sorting dapat dilakukan dengan mudah. Untuk filtering, kita bisa sekreatif mungkin membuat filter dengan merumuskan sebuah kondisi pada DataFrame di dalam dua kurung siku.

Sebagai contoh, kode di bawah ini akan memfilter penumpang Titanic yang berumur di bawah 17 tahun:

df_young = df_titanic[df_titanic['Age'] < 17]

print(df_young)

Hasil filtering akan mengembalikan nilai berupa DataFrame baru. Row pada DataFrame baru hanya row yang masuk dalam kondisi yang telah diset.

Kita juga bisa memfilter penumpang yang selamat (Survived=1) seperti kode di bawah ini:

df_survived = df_titanic[df_titanic['Survived'] == 1]

print(df_survived)

Selain itu, kita juga bisa memfilter penumpang kelas tertentu seperti kode di bawah ini:

df_class = df_titanic[df_titanic['Pclass'].isin([1, 2])]

print(df_class)

Apabila perlu melakukan filtering untuk beberapa kondisi sekaligus, kita dapat menulis kode seperti di bawah ini:

df_survived_and_class_1 = df_titanic[(df_titanic['Survived'] == 1) & (df_titanic['Pclass'] == 1)]
print(df_survived_and_class_1)

Untuk melakukan sorting, kita dapat menggunakan fungsi sort_values seperti contoh di bawah ini:

df_sorted_age = df_titanic.sort_values(by='Age')

print(df_sorted_age)

Seperti halnya filtering, hasil sorting akan mengembalikan nilai berupa DataFrame baru. Row pada DataFrame baru akan mengalami perubahan urutan sesuai dengan column yang kita set.

Secara default, nilai akan diurutkan secara menaik. Apabila kita ingin mengurutkan secara menurun, kita perlu mengeset parameter ascending=False pada fungsi sort_values.

df_sorted_age = df_titanic.sort_values(by='Age', ascending=False)

print(df_sorted_age)

Ringkasan statistik

Pandas memudahkan kita untuk mendapatkan statistik dari sebuah column pada DataFrame dengan beberapa fungsi statistik dasar seperti count, mean, median, std (standar deviasi), min, max dan quantile.

print(df_titanic['Age'].count()) # Output: 714
print(df_titanic['Age'].mean()) # Output: 29.69911764705882
print(df_titanic['Age'].std()) # Output: 14.526497332334044
print(df_titanic['Age'].min()) # Output: 0.42
print(df_titanic['Age'].max()) # Output: 80.0
print(df_titanic['Age'].quantile(0.25)) # Output: 20.125
print(df_titanic['Age'].median()) # Output: 28.0
print(df_titanic['Age'].quantile(0.75)) # Output: 38.0

Kita juga bisa menggunakan fungsi describe untuk mendapatkan beberapa data statistik dari semua column dengan nilai numerik sekaligus.

stat_titanic = df_titanic.describe()
print(stat_titanic)
# Output:
#        PassengerId    Survived      Pclass  ...       SibSp       Parch        Fare
# count   891.000000  891.000000  891.000000  ...  891.000000  891.000000  891.000000
# mean    446.000000    0.383838    2.308642  ...    0.523008    0.381594   32.204208
# std     257.353842    0.486592    0.836071  ...    1.102743    0.806057   49.693429
# min       1.000000    0.000000    1.000000  ...    0.000000    0.000000    0.000000
# 25%     223.500000    0.000000    2.000000  ...    0.000000    0.000000    7.910400
# 50%     446.000000    0.000000    3.000000  ...    0.000000    0.000000   14.454200
# 75%     668.500000    1.000000    3.000000  ...    1.000000    0.000000   31.000000
# max     891.000000    1.000000    3.000000  ...    8.000000    6.000000  512.329200

print(stat_titanic['Age'])
# Output:
# count    714.000000
# mean      29.699118
# std       14.526497
# min        0.420000
# 25%       20.125000
# 50%       28.000000
# 75%       38.000000
# max       80.000000
# Name: Age, dtype: float64

Apabila ingin melakukan kustomisasi pada statistik yang ingin ditampilkan secara sekaligus, kita dapat menggunakan fungsi agg seperti contoh berikut:

stat_age = df_titanic.agg(average=('Age', 'mean'), standard_deviation=('Age', 'std'))
print(stat_age)

# Output:
#                           Age
# average             29.699118
# standard_deviation  14.526497

Dalam melakukan analisis data, seringkali kita perlu mendapatkan statistik dari data yang telah digrouping berdasarkan kategori pada column lain. Pada DataFrame, grouping dapat dilakukan dengan menggunakan fungsi groupby.

# Contoh penggunaan groupby + describe
stat_titanic_class = df_titanic.groupby(['Pclass']).describe()
print(stat_titanic_class)
# Output:
#        PassengerId                          ...     Fare
#              count        mean         std  ...      50%   75%       max
# Pclass                                      ...
# 1            216.0  461.597222  246.737616  ...  60.2875  93.5  512.3292
# 2            184.0  445.956522  250.852161  ...  14.2500  26.0   73.5000
# 3            491.0  439.154786  264.441453  ...   8.0500  15.5   69.5500
#
# [3 rows x 48 columns]

print(stat_titanic_class['Age'])
# Output:
#         count       mean        std   min   25%   50%   75%   max
# Pclass
# 1       186.0  38.233441  14.802856  0.92  27.0  37.0  49.0  80.0
# 2       173.0  29.877630  14.001077  0.67  23.0  29.0  36.0  70.0
# 3       355.0  25.140620  12.495398  0.42  18.0  24.0  32.0  74.0

# Contoh penggunaan groupby + agg
stat_age_class = df_titanic.groupby(['Pclass']).agg(age_average=('Age', 'mean'))
print(stat_age_class)
# Output:
#         age_average
# Pclass
# 1         38.233441
# 2         29.877630
# 3         25.140620

Apabila kamu perhatikan, setelah kita menggunakan fungsi agg yang dikombinasikan dengan fungsi groupby, struktur DataFrame kita berubah. Nilai pada column yang kita set pada fungsi groupby tidak lagi dapat dipanggil seperti biasanya (df['<nama-column>']). Hal ini karena nilai pada column tsb. sudah hilang dan berubah menjadi nama index pada DataFrame. Perhatikan contoh berikut:

# Contoh penggunaan groupby + agg
stat_age_class = df_titanic.groupby(['Pclass']).agg(age_average=('Age', 'mean'))
print(stat_age_class)
# Output:
#         age_average
# Pclass
# 1         38.233441
# 2         29.877630
# 3         25.140620

# Kode ini akan error karena column 'Pclass' tidak ada pada dataframe
print(stat_age_class['Pclass'])
# Output:
#     raise KeyError(key) from err
#
# KeyError: 'Pclass'

# Nilai pada column 'Pclass' berubah menjadi index pada dataframe
print(stat_age_class.index)
# Output:
# Index([1, 2, 3], dtype='int64', name='Pclass')

Ada satu trik yang bisa kita gunakan agar nilai column yang kita set pada fungsi groupby kembali menjadi bagian dari DataFrame, yaitu dengan menggunakan fungsi reset_index seperti contoh berikut:

stat_age_class = df_titanic.groupby(['Pclass']).agg(age_average=('Age', 'mean')).reset_index()
print(stat_age_class)
# Output:
#    Pclass  age_average
# 0       1    38.233441
# 1       2    29.877630
# 2       3    25.140620

print(stat_age_class['Pclass'])
# Output:
# 0    1
# 1    2
# 2    3
# Name: Pclass, dtype: int64

Modifikasi struktur DataFrame

Secara umum, struktur data tabel itu terdiri dari dua macam, yaitu format wide/melebar dan format long/memanjang. Perbedaannya, data dengan format wide menggunakan column untuk menyimpan value untuk tiap variable yang berbeda, sedangkan data dengan format long biasanya menggunakan satu column berisi variable dan satu column berisi value dari variable. Sebagai contoh, data titanic bisa dikategorikan sebagai data dengan format wide karena tiap variable dan value-nya (Survived, Pclass dsb.) dijabarkan ke dalam column yang terpisah.

import pandas as pd

titanic = pd.read_csv('https://raw.githubusercontent.com/pandas-dev/pandas/main/doc/data/titanic.csv', delimiter = ',')

print(titanic)
# Output:
#      PassengerId  Survived  Pclass  ...     Fare Cabin  Embarked
# 0              1         0       3  ...   7.2500   NaN         S
# 1              2         1       1  ...  71.2833   C85         C
# 2              3         1       3  ...   7.9250   NaN         S
# 3              4         1       1  ...  53.1000  C123         S
# 4              5         0       3  ...   8.0500   NaN         S
# ..           ...       ...     ...  ...      ...   ...       ...
# 886          887         0       2  ...  13.0000   NaN         S
# 887          888         1       1  ...  30.0000   B42         S
# 888          889         0       3  ...  23.4500   NaN         S
# 889          890         1       1  ...  30.0000  C148         C
# 890          891         0       3  ...   7.7500   NaN         Q
#
# [891 rows x 12 columns]

Apabila kita perlu mengubah format data titanic menjadi long, kita dapat menggunakan fungsi melt seperti contoh di bawah ini:

columns = ['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age',
    'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked']

titanic_long = data.melt(titanic, id_vars = ['PassengerId'], value_vars = columns)

print(titanic_long)
# Output:
#       PassengerId  variable value
# 0               1  Survived     0
# 1               2  Survived     1
# 2               3  Survived     1
# 3               4  Survived     1
# 4               5  Survived     0
#           ...       ...   ...
# 9796          887  Embarked     S
# 9797          888  Embarked     S
# 9798          889  Embarked     S
# 9799          890  Embarked     C
# 9800          891  Embarked     Q
#
# [9801 rows x 3 columns]

Pada contoh di atas, kita mengeset parameter id_vars = ['PassengerId'] sebagai column acuan (index), dan parameter value_vars = columns sebagai column yang ingin kita gabung. Hasilnya akan menjadi DataFrame baru dengan 3 column: PassengerId, variable yang value-nya adalah nama column variable pada parameter value_vars, dan value yang berisi value asli dari variablenya. Apabila diperhatikan, jumlah row pada DataFrame dengan format long lebih besar dibandingkan pada format wide.

Kita juga bisa mengkonversi DataFrame dengan format long menjadi wide menggunakan fungsi pivot seperti contoh berikut:

titanic_wide = titanic_long \
    .pivot(index = 'PassengerId', columns = 'variable', values = 'value') \
    .reset_index()

print(titanic_wide)
# Output:
# variable  PassengerId   Age Cabin  ... SibSp Survived            Ticket
# 0                   1  22.0   NaN  ...     1        0         A/5 21171
# 1                   2  38.0   C85  ...     1        1          PC 17599
# 2                   3  26.0   NaN  ...     0        1  STON/O2. 3101282
# 3                   4  35.0  C123  ...     1        1            113803
# 4                   5  35.0   NaN  ...     0        0            373450
# ..                ...   ...   ...  ...   ...      ...               ...
# 886               887  27.0   NaN  ...     0        0            211536
# 887               888  19.0   B42  ...     0        1            112053
# 888               889   NaN   NaN  ...     1        0        W./C. 6607
# 889               890  26.0  C148  ...     0        1            111369
# 890               891  32.0   NaN  ...     0        0            370376
#
# [891 rows x 12 columns]