.
Perkenalkan saya Faris Dedi Setiawan, Owner Whitecyber dan Pembina Data Engineer. Data Engineering sangat menarik untuk saya, Data Engineering adalah bagian dari Data Science yang sangat penting. Data Engineering masih belum banyak mendapatkan sorotan di Indonesia, tetapi ini adalah salah satu profesi/bidang yang sangat menjanjikan, karena tidak banyak orang yang tahu bagaimana harus menjadi Data Engineer.
Di pembahasan kali ini, saya akan membahas tentang Basic Feature Engineering untuk Modelling. Semoga dapat bermanfaat untuk kita semua.
.
.
Feature Engineering
Feature Engineering adalah proses dimana kita menerapkan pengetahuan yang kita punya untuk mendapatkan informasi yang lebih dari data yang kita punya. Contohnya dari KTP seseorang, anda sebenarnya dapat mendapatkan domisili, pembuatan KTP, tanggal lahir, usia, dan jenis kelamin. Anda dapat menggolongkan orang-orang dengan kategori yang sama untuk membuat machine learning lebih mudah membedakan ciri orang.
Dataset
Di pembahasan kali ini saya menggunakan dataset titanic yang sangat terkenal dan sering digunakan. Dataset ini berasal dari Kaggle, salah satu situs kompetisi machine learning. Dataset ini terdiri dari 2 file, titanic_train.csv dan titanic_test.csv. Untuk lebih mudah mengenali data ini, kita akan langsung memulai praktek untuk meng-eksplor data dengan Python.
Library
Import library python biasanya dilakukan di awal sebuah projek. Library yang kita akan gunakan antara lain:
- pandas untuk proses dataframe dan csv
- matplotlib untuk plotting grafik
- seaborn untuk plotting grafik
- sklearn untuk machine learning model
- string untuk proses string
Import Data Set dan Concat Data Frame
Dataset ini adalah dataset Titanic asli yang didapatkan dari Kaggle. Berisi data dari semua orang yang ikut di dalam Kapal Titanic ratusan tahun yang lalu. Jadi, di dalam dataset ini kita mempunyai target variable/label yaitu Survived. Semua kolom/fitur lain akan digunakan untuk menentukkan apakah penumpang ini selamat/tidak dari kejadian Titanic.
Data Train digunakan untuk melatih model machine learning kita. Data Test nantinya digunakan untuk menebak akurasi model kita di Kaggle.
Pada penjelasan ini teman-teman akan dijelakan untuk melakukan membaca data dari file csv dan melakukan concat dataframe dengan membuat sebuah fungsi.
1. Buat Function concat_df digunakan untuk menggabungkan dua dataset/dataframe dari 2 csv menjadi satu dataframe
def concat_df(train_data, test_data): # Returns a concatenated df of training and test set return pd.concat([train_data, test_data], sort=True).reset_index(drop=True)
.
2. Untuk memasukkan csv ke dalam Pandas Dataframe, kita harus menggunakan pd.read_csv()
Data train kita masukkan ke df_train dan Data test kita masukkan ke df_test. df_all adalah gabungan dari kedua dataframe.
df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test)
.
3. Kita dapat menamai tiap dataframe dengan memberikan “name” untuk masing-masing dataframe dengan cara
df_train.name = 'training Set' df_test.name = 'Test Set
.
4. dfs adalah list yang berisi kedua dataframe.
.
dfs = [df_train, df_test]
.
Penjelasan dari dataset
- PassengerId adalah id pada row, maka tidak ada pengaruh terhadap target yang dicari
- Survived adalah target yang akan diprediksi, nilai 0 = Not Survived dan nilai 1 = Survived
- Pclass (Passenger Class) adalah kategori level sosial ekonomi penumpang dengan nilai (1, 2 atau 3):
1 = Upper Class
2 = Middle Class
3 = Lower Class
- Name, Sex dan Age merupakan data self-explanatory
- SibSp adalah jumlah saudara dari penumpang
- Parch adalah jumlah Orang Tua dan anak dari penumpang
- Ticket adalah jumlah tiket penumpang
- Fare adalah tarif yang di kenakan kepada penumpang
- Cabin adalah nomor kabin penumpang
- Embarked adalah pelabuhan pemberangkatan ada 3 pelabuhan (C, Q atau S):
C = Cherbourg
Q = Queenstown
S = Southampton
Exploring Data
Untuk mengetahui bentuk dari dataframe kita, berapa banyak row dan column yang ada di dalamnya, kita dapat menggunakan .shape. gunakan .columns untuk mendapatkan column yang ada pada dataframe
Code
print('Number of Training Examples = {}'.format(df_train.shape[0])) print('Number of Test Examples = {}\n'.format(df_test.shape[0])) print('Training X Shape = {}'.format(df_train.shape)) print('Training y Shape = {}\n'.format(df_train['Survived'].shape[0])) print('Test X Shape = {}'.format(df_test.shape)) print('Test y Shape = {}\n'.format(df_test.shape[0])) print(df_train.columns) print(df_test.columns)
.
Hasilnya adalah
Missing Value dan Contoh data
Salah satu cara untuk menemukan Missing value pada data Anda dapat menggunakan : .info(memory_usage=False)
Sekarang, Anda diminta untuk mengeluarkan missing value pada dataframe df_train. Bila dijalankan, maka mengeluarkan di bawah ini
df_train.info(memory_usage=False) .
Kita dapat melihat bahwa ada beberapa data yang kosong di kolom ‘Embarked, ‘Age’, dan ‘Cabin’
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId 891 non-null int64
Survived 891 non-null int64
Pclass 891 non-null int64
Name 891 non-null object
Sex 891 non-null object
Age 714 non-null float64
SibSp 891 non-null int64
Parch 891 non-null int64
Ticket 891 non-null object
Fare 891 non-null float64
Cabin 204 non-null object
Embarked 889 non-null object
.
Untuk melihat bagian awal dari data Anda dapat menggunakan
.head(10)
print(df_train.head(10))
.
Keluarkan 10 data awal pada dataframe df_train sehingga mengeluarkan:
dtypes: float64(2), int64(5), object(5) 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 6 0 3 ... 8.4583 NaN Q
6 7 0 1 ... 51.8625 E46 S
7 8 0 3 ... 21.0750 NaN S
8 9 1 3 ... 11.1333 NaN S
9 10 1 2 ... 30.0708 NaN C
[10 rows x 12 columns]
.
Mencari korelasi dan melakukan data cleansing sederhana
Mengetahui Korelasi Fitur
Untuk mencari korelasi antar kolom pada sebuah dataframe, Anda dapat menggunakan corr().abs() seperti contoh penggunaannya di bawah ini:
.
df_train_corr = df_train.corr().abs() print(df_train_corr.to_string())
.
Hasilnya
.
PassengerId Survived Pclass Age SibSp Parch Fare
PassengerId 1.000000 0.005007 0.035144 0.036847 0.057527 0.001652 0.012658
Survived 0.005007 1.000000 0.338481 0.077221 0.035322 0.081629 0.257307
Pclass 0.035144 0.338481 1.000000 0.369226 0.083081 0.018443 0.549500
Age 0.036847 0.077221 0.369226 1.000000 0.308247 0.189119 0.096067
SibSp 0.057527 0.035322 0.083081 0.308247 1.000000 0.414838 0.159651
Parch 0.001652 0.081629 0.018443 0.189119 0.414838 1.000000 0.216225
Fare 0.012658 0.257307 0.549500 0.096067 0.159651 0.216225 1.000000
.
Membaca hasil korelasi fitur
Apabila Anda melihat table ini Anda akan mengetahui korelasi antar kolom. Korelasi dapat ditentukan dengan mendekati nilai 1 untuk korelasi positive dan nilai -1 untuk korelasi terbalik. Pada data ini dapat dilihat bahwa target variable kita Survived sangat besar korelasinya dengan Pclass dan Fare. Sedangkan Age sangat berkaitan dengan Pclass, Sibling Spouse (SibSp), Parent Children (Parch). Dapat diasumsikan bahwa kebanyakan orang yang selamat adalah orang dengan PClass atas dan Tuanya umur seseorang dapat dikatakan dia akan membawa saudara/orang tua/anak/pasangan. Dan Fare (harga) tentu saja berkaitan dengan Pclass (kelas penumpang) seorang penumpang.
.
Mengenali missing data dari kolom
Perhatikan LiveCode terdapat function display_missing. Function tersebut digunakan untuk mengetahui jumlah missing value dari setiap kolom.
.
def display_missing(df): for col in df.columns.tolist(): print('{} column missing values: {}'.format(col, df[col].isnull().sum())) print('\n') for df in dfs: print('{}'.format(df.name)) display_missing(df)
.
Hasilnya adalah sebagai berikut :
.
Training Set
PassengerId column missing values: 0
Survived column missing values: 0
Pclass column missing values: 0
Name column missing values: 0
Sex column missing values: 0
Age column missing values: 177
SibSp column missing values: 0
Parch column missing values: 0
Ticket column missing values: 0
Fare column missing values: 0
Cabin column missing values: 687
Embarked column missing values: 2
Test Set
PassengerId column missing values: 0
Pclass column missing values: 0
Name column missing values: 0
Sex column missing values: 0
Age column missing values: 86
SibSp column missing values: 0
Parch column missing values: 0
Ticket column missing values: 0
Fare column missing values: 1
Cabin column missing values: 327
Embarked column missing values: 0
.
Mencari nilai untuk missing value
Untuk mengisi data Age yang kosong, karena kita mengetahui bahwa Umur seseorang berkaitan dengan Kelas penumpangnya, kita dapat mengisinya dengan nilai tengah umur seseorang di dalam kelas tersebut dan berdasar jenis kelaminnya.
Jadi kita lakukan groupby terhadap Jenis Kelamin dan Kelas Penumpang, lalu isi nilai tersebut ke dalam missing value yang ada di dalam data kita.
.
age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] for pclass in range(1, 4): for sex in ['female', 'male']: print('Median age of Pclass {} {}s: {}'.format(pclass, sex, age_by_pclass_sex[sex][pclass])) print('Median age of all passengers: {}'.format(df_all['Age'].median())) # Filling the missing values in Age with the medians of Sex and Pclass groups df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median()))
.
Hasilnya
.
Median age of Pclass 1 females: 36.0
Median age of Pclass 1 males: 42.0
Median age of Pclass 2 females: 28.0
Median age of Pclass 2 males: 29.5
Median age of Pclass 3 females: 22.0
Median age of Pclass 3 males: 25.0
Median age of all passengers: 28.0
.
Mengisi nilai kosong
Kita juga harus mengisi nilai yang hilang untuk kolom Embarked dan Fare. Untuk Embarked, kebanyakan orang dari Titanic berangkat dari Southampton/S, sehingga kita dapat mengisinya dengan S saja. Ini lebih baik daripada membiarkan datanya kosong. Untuk Fare, kita tahu bahwa Fare sangat berkaitan dengan Kelas Penumpang, Jumlah Parent/Children, dan Jumlah Sibling/Spouse. Sehingga kita dapat mengisinya dengan nilai tengah dari orang yang berada di grup tersebut.
.
age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) # Filling the missing values in Embarked with S df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] # Filling the missing value in Fare with the median Fare of 3rd class alone passenger df_all['Fare'] = df_all['Fare'].fillna(med_fare)
.
Exploring data
Dari plot yang dihasikan kita dapat melihat, ternyata penumpang yang berangkat dari Cherbourg lebih banyak yang selamat, sedangkan penumpang dari Southampton, hanya setengahnya yang selamat. Untuk orang yang membawa hanya 1 Parent/Children, lebih banyak yang selamat. Untuk orang dengan Kelas Penumpang 1, kemungkinan selamatnya jauh lebih tinggi. Dan penumpang dengan Kelas Penumpang 3 hanya sedikit yang selamat. Dan Orang yang membawa 1 Sibling/Spouse kemungkinan selamatnya jauh lebih besar. Orang yang membawa 2 Sibling/Spouse kemungkinan selamatnya cukup kecil.
.
cat_features = ['Embarked', 'Parch', 'Pclass', 'Sex', 'SibSp'] fig, axs = plt.subplots(ncols=2, nrows=3, figsize=(20, 20)) plt.subplots_adjust(right=1.5, top=1.25) for i, feature in enumerate(cat_features, 1): plt.subplot(2, 3, i) sns.countplot(x=feature, hue='Survived', data=df_train) plt.xlabel('{}'.format(feature), size=20, labelpad=15) plt.ylabel('Passenger Count', size=20, labelpad=15) plt.tick_params(axis='x', labelsize=20) plt.tick_params(axis='y', labelsize=20) plt.legend(['Not Survived', 'Survived'], loc='upper center', prop={'size': 18}) plt.title('Count of Survival in {} Feature'.format(feature), size=20, y=1.05) plt.tight_layout() plt.show()
.
Hasilnya adalah sebagai berikut :
.
.
Exploring data part 2
Untuk Data Fare dan Age, kita akan membaginya ke dalam beberapa Bin/Group. Dari fungsi describe sebelumnya, kita tahu bahwa minimal usia yang ada adalah 0.17 tahun dan yang tertua adalah 80 tahun. Sehingga saya rasa membaginya dengan 13 kelompok quantile cukup. Dan untuk Fare termurah adalah 0 dan termahal adalah 512 (lihat hasil statistik dekriptifnya). Sehingga saya rasa membaginya dengan 10 kelompok quantile cukup. Perintah yang pertama bermaksud untuk membagi Fare menjadi 13 bagian dengan fungsi qcut().
Dan perintah yang kedua adalah untuk menggambarkan plot group usia terhadap tingkat keselamatan. Dapat dilihat bahwa semakin mahal harga tiketnya, semakin besar kemungkinan orang itu selamat, dimulai dari harga 56 ke atas. Tetapi banyak orang yang selamat dimulai dari 10.5 sudah cukup meningkat, kecuali kejadian yang terjadi pada kelompok pemegang tiket berharga 13-15.742.
.
age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) fig, axs = plt.subplots(figsize=(22, 9)) sns.countplot(x='Fare', hue='Survived', data=df_all) plt.xlabel('Fare', size=15, labelpad=20) plt.ylabel('Passenger Count', size=15, labelpad=20) plt.tick_params(axis='x', labelsize=10) plt.tick_params(axis='y', labelsize=15) plt.legend(['Not Survived', 'Survived'], loc='upper right', prop={'size': 15}) plt.title('Count of Survival in {} Feature'.format('Fare'), size=15, y=1.05) plt.tight_layout() plt.show()
.
Hasilnya adalah sebagai berikut :
.
.
Note:
Untuk pembagian jumlah bins yang berbeda baik 13 bins untuk “Age” dan 10 bins untuk “Fare” tidak aturan bakunya. Tetapi yang diinginkan dari visualisasi berdasarkan pembagian dengan jumlah bins adalah sebaran datanya. Sebagai contoh untuk “Age” yang memiliki range data 0 (min) s/d 80 (max). Untuk itu, awalnya membagi data menjadi 8 bins katakanlah cukup untuk mereprsentasikan sebaran data. Ketika setelah dicek dengan visualisasi sebarannya belum mewakili dan adanya skew. Selanjutnya, kita dapat menaikkan/menurunkan jumlah bins untuk melihat sebaran data berikut. Untuk “Age” ini terpilihlah 13 bins yang cocok untuk mepresentasikan sebaran data. Dengan cara yang sama dapat juga diterapkan untuk “Fare”. Jadi tidak ada aturan baku yang mengatur jumlah bins tersebut.
.
Feature Engineering – Part 1
Feature Engineering adalah tentang membuat fitur baru dari fitur yang sudah ada. Dari sini kita akan membuat beberapa fitur baru yang bertujuan menaikkan akurasi dari model machine learning kita. Fitur pertama yang kita buat adalah Family_Size, sesuai namanya ini adalah gabungan dari Parent, Children, Sibling, dan Spouse. Lalu kita tambahkan 1 dengan asumsi menghitung diri orang itu juga.
df_all[‘Family_Size’] = df_all[‘SibSp’] + df_all[‘Parch’] + 1
Untuk melihat nilai distinct dari Family_Size, anda dapat menjalankan perintah:
df_all[‘Family_Size’].unique()
Fitur kedua yang kita buat adalah menggabungkan Family_Size dengan groupnya masing-masing tergantung jumlahnya.
Kategorinya adalah seperti berikut.
Family Size 1 = Alone
Family Size 2, 3 dan 4 = Small
Family Size 5 dan 6 = Medium
Family Size 7, 8 dan 11 = Large
df_all[‘Family_Size_Grouped’] = df_all[‘Family_Size’].map(family_map)
Setelah itu kita gambarkan plotnya.
Anda perhatikan code pada livecode dan jalankan. Pada plot menjelaskan bahwa orang dengan Family_Size 2,3,4 mempunyai kemungkinan selamat lebih besar, selebihnya kemungkinannya menurun dan orang yang pergi dengan Family_Size_Grouped Small lebih terlihat mempunyai tingkat keselamatan lebih besar.
Codenya sebagai berikut :
.
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns sns.set(style="darkgrid") def concat_df(train_data, test_data): return pd.concat([train_data, test_data], sort=True).reset_index(drop=True) df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test) df_train.name = 'Training Set' df_test.name = 'Test Set' df_all.name = 'All Set' dfs = [df_train, df_test] age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) df_all['Family_Size'] = df_all['SibSp'] + df_all['Parch'] + 1 fig, axs = plt.subplots(figsize=(20, 20), ncols=2, nrows=2) plt.subplots_adjust(right=1.5) sns.barplot(x=df_all['Family_Size'].value_counts().index, y=df_all['Family_Size'].value_counts().values, ax=axs[0][0]) sns.countplot(x='Family_Size', hue='Survived', data=df_all, ax=axs[0][1]) axs[0][0].set_title('Family Size Feature Value Counts', size=20, y=1.05) axs[0][1].set_title('Survival Counts in Family Size ', size=20, y=1.05) family_map = {1: 'Alone', 2: 'Small', 3: 'Small', 4: 'Small', 5: 'Medium', 6: 'Medium', 7: 'Large', 8: 'Large', 11: 'Large'} df_all['Family_Size_Grouped'] = df_all['Family_Size'].map(family_map) sns.barplot(x=df_all['Family_Size_Grouped'].value_counts().index, y=df_all['Family_Size_Grouped'].value_counts().values, ax=axs[1][0]) sns.countplot(x='Family_Size_Grouped', hue='Survived', data=df_all, ax=axs[1][1]) axs[1][0].set_title('Family Size Feature Value Counts After Grouping', size=20, y=1.05) axs[1][1].set_title('Survival Counts in Family Size After Grouping', size=20, y=1.05) for i in range(2): axs[i][1].legend(['Not Survived', 'Survived'], loc='upper right', prop={'size': 20}) for j in range(2): axs[i][j].tick_params(axis='x', labelsize=20) axs[i][j].tick_params(axis='y', labelsize=20) axs[i][j].set_xlabel('') axs[i][j].set_ylabel('') plt.tight_layout() plt.show()
.
Hasilnya adalah sebagai berikut :
.
.
Feature Engineering – Part 2
Kita buat feature baru bernama Ticket_Frequency dengan nilai gabungan dari Ticket yang sama. Contoh sebelumnya akan bernilai 6, karena ada 6 ticket yang sama dalam data kita. Anda diminta untuk melengkapi bagian […1…] dengan menghitung hasil dari grouping pada kolom Ticket dan pada bagian […2…] untuk mengeluarkan plot tersebut. Pada hasil plot penjelasannya feature Family_Size_Grouped, di angka 2,3,4 kemungkinan tingkat selamatnya meningkat. Kenapa feature ini berbeda dari Family_Size_Grouped? Karena bisa jadi ada pembantu, teman yang menggunakan tiket yang sama tetapi tidak terhitung sebagai keluarga.
.
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns sns.set(style="darkgrid") def concat_df(train_data, test_data): return pd.concat([train_data, test_data], sort=True).reset_index(drop=True) df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test) df_train.name = 'Training Set' df_test.name = 'Test Set' df_all.name = 'All Set' dfs = [df_train, df_test] age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) df_all['Family_Size'] = df_all['SibSp'] + df_all['Parch'] + 1 family_map = {1: 'Alone', 2: 'Small', 3: 'Small', 4: 'Small', 5: 'Medium', 6: 'Medium', 7: 'Large', 8: 'Large', 11: 'Large'} df_all['Family_Size_Grouped'] = df_all['Family_Size'].map(family_map) df_all['Ticket_Frequency'] = df_all.groupby('Ticket')['Ticket'].transform('count') fig, axs = plt.subplots(figsize=(12, 9)) sns.countplot(x='Ticket_Frequency', hue='Survived', data=df_all) plt.xlabel('Ticket Frequency', size=15, labelpad=20) plt.ylabel('Passenger Count', size=15, labelpad=20) plt.tick_params(axis='x', labelsize=15) plt.tick_params(axis='y', labelsize=15) plt.legend(['Not Survived', 'Survived'], loc='upper right', prop={'size': 15}) plt.title('Count of Survival in {} Feature'.format('Ticket Frequency'), size=15, y=1.05) plt.tight_layout() plt.show()
.
Hasilnya adalah :
.
.
Feature Engineering – Part 3
Jika anda lihat pada contoh di atas, dari nama orang yang ada di dataset ini, semuanya mempunyai pola yang sama, yaitu:
[Nama_belakang], [Jabatan]. [Nama_depan]
sehingga kita bisa mengambil jabatannya saja dengan mengambil kata setelah “,” (koma) dan sebelum “.” (titik). Fungsi .split() akan membagi kalimat menjadi beberapa kata dengan keyword tertentu, dan dapat diambil dengan index [ ]
Gantilah bagian […1…] untuk menghasilkan seperti di bawah ini:
[Braund, Mr. , Owen Harris]
Lalu fungsi lakukan split untuk bagian kedua yang akan menghasilkan:
[Mr, Owen Harris]
Lalu kita ambil index 0 alias yang pertama sehingga akan mendapatkan Mr
Dari sini kita bisa membuat fitur baru dengan nama ‘Title’ yang berisi jabatan seseorang.
Jabatan yang paling umum di sini adalah Mr, Mrs. , dan Miss.
Sehingga kita bisa mengetahui status menikah seseorang dari Mrs.
Kita bisa membuat fitur baru lagi yaitu ‘Is_Married’
Fitur ini adalah jika seseorang mempunyai jabatan ‘Mrs’ , berarti dia sudah menikah.
Lalu kita buat grafik plot nya
Setelah melakukan df_all[‘Title’].unique()
Ternyata ada banyak sekali jabatan lain, dan kita mengelompokkannya menjadi satu pada konten berikutnya
[‘Miss’, ‘Mrs’,’Ms’, ‘Mlle’, ‘Lady’, ‘Mme’, ‘the Countess’, ‘Dona’] akan kita ubah menjadi ‘Miss/Mrs/Ms’
[‘Dr’, ‘Col’, ‘Major’, ‘Jonkheer’, ‘Capt’, ‘Sir’, ‘Don’, ‘Rev’] menjadi ‘Dr/Military/Noble/Clergy’
.
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns sns.set(style="darkgrid") def concat_df(train_data, test_data): return pd.concat([train_data, test_data], sort=True).reset_index(drop=True) df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test) df_train.name = 'Training Set' df_test.name = 'Test Set' df_all.name = 'All Set' dfs = [df_train, df_test] age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) df_all['Family_Size'] = df_all['SibSp'] + df_all['Parch'] + 1 family_map = {1: 'Alone', 2: 'Small', 3: 'Small', 4: 'Small', 5: 'Medium', 6: 'Medium', 7: 'Large', 8: 'Large', 11: 'Large'} df_all['Family_Size_Grouped'] = df_all['Family_Size'].map(family_map) df_all['Ticket_Frequency'] = df_all.groupby('Ticket')['Ticket'].transform('count') df_all['Title'] = df_all['Name'].str.split(', ', expand=True)[1].str.split('.', expand=True)[0] print(df_all['Title'].unique()) df_all['Is_Married'] = 0 df_all['Is_Married'].loc[df_all['Title'] == 'Mrs'] = 1 print(df_all['Title'].unique())
.
Hasilnya adalah sebagai berikut
.
['Mr' 'Mrs' 'Miss' 'Master' 'Don' 'Rev' 'Dr' 'Mme' 'Ms' 'Major' 'Lady'
'Sir' 'Mlle' 'Col' 'Capt' 'the Countess' 'Jonkheer' 'Dona']
['Mr' 'Mrs' 'Miss' 'Master' 'Don' 'Rev' 'Dr' 'Mme' 'Ms' 'Major' 'Lady'
'Sir' 'Mlle' 'Col' 'Capt' 'the Countess' 'Jonkheer' 'Dona']
.
Feature Engineering – Part 4
Ketikan perintah di bawah ini:
.
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns sns.set(style="darkgrid") def concat_df(train_data, test_data): return pd.concat([train_data, test_data], sort=True).reset_index(drop=True) df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test) df_train.name = 'Training Set' df_test.name = 'Test Set' df_all.name = 'All Set' dfs = [df_train, df_test] age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) df_all['Family_Size'] = df_all['SibSp'] + df_all['Parch'] + 1 family_map = {1: 'Alone', 2: 'Small', 3: 'Small', 4: 'Small', 5: 'Medium', 6: 'Medium', 7: 'Large', 8: 'Large', 11: 'Large'} df_all['Family_Size_Grouped'] = df_all['Family_Size'].map(family_map) df_all['Ticket_Frequency'] = df_all.groupby('Ticket')['Ticket'].transform('count') df_all['Title'] = df_all['Name'].str.split(', ', expand=True)[1].str.split('.', expand=True)[0] df_all['Is_Married'] = 0 df_all['Is_Married'].loc[df_all['Title'] == 'Mrs'] = 1 fig, axs = plt.subplots(nrows=2, figsize=(20, 20)) sns.barplot(x=df_all['Title'].value_counts().index, y=df_all['Title'].value_counts().values, ax=axs[0]) axs[0].tick_params(axis='x', labelsize=10) axs[1].tick_params(axis='x', labelsize=15) for i in range(2): axs[i].tick_params(axis='y', labelsize=15) axs[0].set_title('Title Feature Value Counts', size=20, y=1.05) df_all['Title'] = df_all['Title'].replace(['Miss', 'Mrs','Ms', 'Mlle', 'Lady', 'Mme', 'the Countess', 'Dona'], 'Miss/Mrs/Ms') df_all['Title'] = df_all['Title'].replace(['Dr', 'Col', 'Major', 'Jonkheer', 'Capt', 'Sir', 'Don', 'Rev'], 'Dr/Military/Noble/Clergy') sns.barplot(x=df_all['Title'].value_counts().index, y=df_all['Title'].value_counts().values, ax=axs[1]) axs[1].set_title('Title Feature Value Counts After Grouping', size=20, y=1.05) plt.tight_layout() plt.show()
.
dan jalankan.
df_all[‘Title’] = df_all[‘Title’].replace([‘Miss’, ‘Mrs’,’Ms’, ‘Mlle’, ‘Lady’, ‘Mme’, ‘the Countess’, ‘Dona’], ‘Miss/Mrs/Ms’)
df_all[‘Title’] = df_all[‘Title’].replace([‘Dr’, ‘Col’, ‘Major’, ‘Jonkheer’, ‘Capt’, ‘Sir’, ‘Don’, ‘Rev’], ‘Dr/Military/Noble/Clergy’)
Bagian ini adalah bagian mengubah [‘Miss’, ‘Mrs’,’Ms’, ‘Mlle’, ‘Lady’, ‘Mme’, ‘the Countess’, ‘Dona’] akan kita ubah menjadi ‘Miss/Mrs/Ms’ [‘Dr’, ‘Col’, ‘Major’, ‘Jonkheer’, ‘Capt’, ‘Sir’, ‘Don’, ‘Rev’] menjadi ‘Dr/Military/Noble/Clergy’
Hasilnya adalah :
.
.
Final Check
Untuk melihat apa saja yang telah dilakukan dalam Feature Engineering, Anda dapat melihat dengan menggunakan head().
Pada bagian ini Anda keluarkan 5 baris awal pada dataframe all (df_all).
.
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns sns.set(style="darkgrid") def concat_df(train_data, test_data): return pd.concat([train_data, test_data], sort=True).reset_index(drop=True) df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test) df_train.name = 'Training Set' df_test.name = 'Test Set' df_all.name = 'All Set' dfs = [df_train, df_test] age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) df_all['Family_Size'] = df_all['SibSp'] + df_all['Parch'] + 1 family_map = {1: 'Alone', 2: 'Small', 3: 'Small', 4: 'Small', 5: 'Medium', 6: 'Medium', 7: 'Large', 8: 'Large', 11: 'Large'} df_all['Family_Size_Grouped'] = df_all['Family_Size'].map(family_map) df_all['Ticket_Frequency'] = df_all.groupby('Ticket')['Ticket'].transform('count') df_all['Title'] = df_all['Name'].str.split(', ', expand=True)[1].str.split('.', expand=True)[0] df_all['Is_Married'] = 0 df_all['Is_Married'].loc[df_all['Title'] == 'Mrs'] = 1 df_all['Title'] = df_all['Title'].replace(['Miss', 'Mrs','Ms', 'Mlle', 'Lady', 'Mme', 'the Countess', 'Dona'], 'Miss/Mrs/Ms') df_all['Title'] = df_all['Title'].replace(['Dr', 'Col', 'Major', 'Jonkheer', 'Capt', 'Sir', 'Don', 'Rev'], 'Dr/Military/Noble/Clergy') print(df_all.head(5))
.
Hasilnya adalah
.
Age Cabin Embarked ... Ticket_Frequency Title Is_Married
0 22.0 NaN S ... 1 Mr 0
1 38.0 C85 C ... 2 Miss/Mrs/Ms 1
2 26.0 NaN S ... 1 Miss/Mrs/Ms 0
3 35.0 C123 S ... 2 Miss/Mrs/Ms 1
4 35.0 NaN S ... 1 Mr 0
[5 rows x 17 columns]
.
Modelling dengan hasil Feature Engineering – Part 1
Karena di sini saya tidak akan membahas detil tentang Modelling part, mohon terima saja semuanya terlebih dahulu. Yang kita inginkan adalah menaikkan akurasi dari model kita dengan Feature Engineering.
Pertanyaan nya apakah benar kita bisa menaikkan akurasi modelnya?
Bagian ini akan menjawab hasilnya.
df_train = df_all.loc[:890] df_test = df_all.loc[891:] dfs = [df_train, df_test]
.
Perintah pertama bertujuan untuk membagi kembali dataset kita menjadi train dan test
.
non_numeric_features = [‘Embarked’, ‘Sex’, ‘Title’, ‘Family_Size_Grouped’, ‘Age’, ‘Fare’]
for df in dfs:
for feature in non_numeric_features:
df[feature] = LabelEncoder().fit_transform(df[feature])
.
Perintah kedua adalah LabelEncoder untuk data” yang bersifat non-numeric, tujuannya adalah melakukan encoding [0-n] untuk data kategorikal. Contohnya Sex, akan dirubah menjadi 0 dan 1, laki-laki dan perempuan.
.
cat_features = [‘Pclass’, ‘Sex’, ‘Embarked’, ‘Title’, ‘Family_Size_Grouped’]
encoded_features = []
for df in dfs:
for feature in cat_features:
encoded_feat = OneHotEncoder().fit_transform(df[feature].values.reshape(-1, 1)).toarray()
n = df[feature].nunique()
cols = [‘{}_{}’.format(feature, n) for n in range(1, n + 1)]
encoded_df = pd.DataFrame(encoded_feat, columns=cols)
encoded_df.index = df.index
encoded_features.append(encoded_df)
df_train = pd.concat([df_train, *encoded_features[:5]], axis=1)
df_test = pd.concat([df_test, *encoded_features[5:]], axis=1)
.
Perintah ketiga bertujuan untuk mengubah feature kategori menjadi one hot, dengan OneHotEncoder. Akan menghasilkan beberapa kolom tergantung banyaknya kategori.
Contohnya Pclass akan menjadi 3 kolom Pclass_1, Pclass_2, dan Pclass_3. Isinya adalah 0 dan 1 tergantung kategori orang tersebut.
Kode Lengkapnya adalah sebagai berikut :
.
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns sns.set(style="darkgrid") from sklearn.preprocessing import OneHotEncoder, LabelEncoder, StandardScaler def concat_df(train_data, test_data): return pd.concat([train_data, test_data], sort=True).reset_index(drop=True) df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test) df_train.name = 'Training Set' df_test.name = 'Test Set' df_all.name = 'All Set' age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) df_all['Family_Size'] = df_all['SibSp'] + df_all['Parch'] + 1 family_map = {1: 'Alone', 2: 'Small', 3: 'Small', 4: 'Small', 5: 'Medium', 6: 'Medium', 7: 'Large', 8: 'Large', 11: 'Large'} df_all['Family_Size_Grouped'] = df_all['Family_Size'].map(family_map) df_all['Ticket_Frequency'] = df_all.groupby('Ticket')['Ticket'].transform('count') df_all['Title'] = df_all['Name'].str.split(', ', expand=True)[1].str.split('.', expand=True)[0] df_all['Is_Married'] = 0 df_all['Is_Married'].loc[df_all['Title'] == 'Mrs'] = 1 df_all['Title'] = df_all['Title'].replace(['Miss', 'Mrs','Ms', 'Mlle', 'Lady', 'Mme', 'the Countess', 'Dona'], 'Miss/Mrs/Ms') df_all['Title'] = df_all['Title'].replace(['Dr', 'Col', 'Major', 'Jonkheer', 'Capt', 'Sir', 'Don', 'Rev'], 'Dr/Military/Noble/Clergy') df_train = df_all.loc[:890] df_test = df_all.loc[891:] dfs = [df_train, df_test] non_numeric_features = ['Embarked', 'Sex', 'Title', 'Family_Size_Grouped', 'Age', 'Fare'] for df in dfs: for feature in non_numeric_features: df[feature] = LabelEncoder().fit_transform(df[feature]) cat_features = ['Pclass', 'Sex', 'Embarked', 'Title', 'Family_Size_Grouped'] encoded_features = [] for df in dfs: for feature in cat_features: encoded_feat = OneHotEncoder().fit_transform(df[feature].values.reshape(-1, 1)).toarray() n = df[feature].nunique() cols = ['{}_{}'.format(feature, n) for n in range(1, n + 1)] encoded_df = pd.DataFrame(encoded_feat, columns=cols) encoded_df.index = df.index encoded_features.append(encoded_df) df_train = pd.concat([df_train, *encoded_features[:5]], axis=1) df_test = pd.concat([df_test, *encoded_features[5:]], axis=1)
.
Modelling dengan hasil Feature Engineering – Part 2
Kita akan melakukan drop terhadap kolom-kolom yang tidak kita perlukan, atau yang sudah kita encode sebelumnya. Ketikkanlah kode berikut setelah baris komentar: # Silakan diketikkan kodenya di sini.
.
df_all = concat_df(df_train, df_test) drop_cols = ['Cabin', 'Embarked', 'Family_Size', 'Family_Size_Grouped', 'Survived', 'Name', 'PassengerId', 'Pclass', 'Sex', 'Ticket', 'Title'] df_all.drop(columns=drop_cols, inplace=True) print(df_all.head())
.
Kode
.
import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns sns.set(style="darkgrid") def concat_df(train_data, test_data): return pd.concat([train_data, test_data], sort=True).reset_index(drop=True) df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test) df_train.name = 'Training Set' df_test.name = 'Test Set' df_all.name = 'All Set' age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) df_all['Family_Size'] = df_all['SibSp'] + df_all['Parch'] + 1 family_map = {1: 'Alone', 2: 'Small', 3: 'Small', 4: 'Small', 5: 'Medium', 6: 'Medium', 7: 'Large', 8: 'Large', 11: 'Large'} df_all['Family_Size_Grouped'] = df_all['Family_Size'].map(family_map) df_all['Ticket_Frequency'] = df_all.groupby('Ticket')['Ticket'].transform('count') df_all['Title'] = df_all['Name'].str.split(', ', expand=True)[1].str.split('.', expand=True)[0] df_all['Is_Married'] = 0 df_all['Is_Married'].loc[df_all['Title'] == 'Mrs'] = 1 df_all['Title'] = df_all['Title'].replace(['Miss', 'Mrs','Ms', 'Mlle', 'Lady', 'Mme', 'the Countess', 'Dona'], 'Miss/Mrs/Ms') df_all['Title'] = df_all['Title'].replace(['Dr', 'Col', 'Major', 'Jonkheer', 'Capt', 'Sir', 'Don', 'Rev'], 'Dr/Military/Noble/Clergy') df_train = df_all.loc[:890] df_test = df_all.loc[891:] dfs = [df_train, df_test] df_all = concat_df(df_train, df_test) drop_cols = ['Cabin', 'Embarked', 'Family_Size', 'Family_Size_Grouped', 'Survived', 'Name', 'PassengerId', 'Pclass', 'Sex', 'Ticket', 'Title'] df_all.drop(columns=drop_cols, inplace=True) print(df_all.head())
.
Hasilnya adalah sebagai berikut :
.
Age Fare Is_Married Parch SibSp Ticket_Frequency
0 22.0 (-0.001, 7.25] 0 0 1 1
1 38.0 (56.496, 83.475] 1 0 1 2
2 26.0 (7.896, 8.05] 0 0 0 1
3 35.0 (34.075, 56.496] 1 0 1 2
4 35.0 (7.896, 8.05] 0 0 0 1
.
Modelling dengan hasil Feature Engineering – Part 3
Ketikkan perintah di bawah ini mulai di baris ke-63
.
X_train = StandardScaler().fit_transform(df_train.drop(columns=drop_cols)) y_train = df_train['Survived'].values X_test = StandardScaler().fit_transform(df_test.drop(columns=drop_cols)) print('X_train shape: {}'.format(X_train.shape)) print('y_train shape: {}'.format(y_train.shape)) print('X_test shape: {}'.format(X_test.shape))
.
Setelah kita membagi train dan test untuk modelling seperti ini, kita akan melakukan modelling
.
Modelling dengan hasil Feature Engineering – Part 4
Kita akan menggunakan RandomForestClassifier dari SkLearn dan menghitung akurasi menggunakan cross_val_score
.
from sklearn.ensemble import RandomForestClassifier random_forest = RandomForestClassifier(criterion='gini', n_estimators=1100, max_depth=5, min_samples_split=4, min_samples_leaf=5, max_features='auto', oob_score=True, random_state=50) random_forest.fit(X_train, y_train) . from sklearn.model_selection import cross_val_score scores = cross_val_score(random_forest, X_train, y_train, cv=10, scoring = "accuracy") print("Scores:", scores) print("Mean:", scores.mean()) print("Standard Deviation:", scores.std())
.
Hasil akurasi nya dengan menggunakan feature dari feature engineering adalah sekitar 0.832 sesuai di gambar
.
.
Modelling tanpa hasil Feature Engineering – Part 1
Sekarang kita akan modelling lagi tanpa menyertakan fitur yang sudah kita buat.
Ketikkan semua kode yang ada di bawah ini mulai dari baris 59
.
df_all = concat_df(df_train, df_test) drop_cols = ['Cabin', 'Embarked', 'Family_Size', 'Family_Size_Grouped', 'Survived', 'Name', 'PassengerId', 'Pclass', 'Sex', 'Ticket', 'Title', 'Family_Size_Grouped_1', 'Family_Size_Grouped_2', 'Family_Size_Grouped_3', 'Family_Size_Grouped_4', 'Ticket_Frequency', 'Title_1', 'Title_2', 'Title_3', 'Title_4', 'Is_Married'] df_all.drop(columns=drop_cols, inplace=True) print(df_all.head())
.
X_train = StandardScaler().fit_transform(df_train.drop(columns=drop_cols)) y_train = df_train['Survived'].values X_test = StandardScaler().fit_transform(df_test.drop(columns=drop_cols)) print('X_train shape: {}'.format(X_train.shape)) print('y_train shape: {}'.format(y_train.shape)) print('X_test shape: {}'.format(X_test.shape))
.
Code Lengkapnya sebagai berikut
.
import numpy as np import pandas as pd from sklearn.preprocessing import OneHotEncoder, LabelEncoder, StandardScaler def concat_df(train_data, test_data): return pd.concat([train_data, test_data], sort=True).reset_index(drop=True) df_train = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_train.csv') df_test = pd.read_csv('https://storage.googleapis.com/dqlab-dataset/challenge/feature-engineering/titanic_test.csv') df_all = concat_df(df_train, df_test) df_train.name = 'Training Set' df_test.name = 'Test Set' df_all.name = 'All Set' age_by_pclass_sex = df_all.groupby(['Sex', 'Pclass']).median()['Age'] df_all['Age'] = df_all.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median())) df_all['Embarked'] = df_all['Embarked'].fillna('S') med_fare = df_all.groupby(['Pclass', 'Parch', 'SibSp']).Fare.median()[3][0][0] df_all['Fare'] = df_all['Fare'].fillna(med_fare) df_all['Fare'] = pd.qcut(df_all['Fare'], 13) df_all['Family_Size'] = df_all['SibSp'] + df_all['Parch'] + 1 family_map = {1: 'Alone', 2: 'Small', 3: 'Small', 4: 'Small', 5: 'Medium', 6: 'Medium', 7: 'Large', 8: 'Large', 11: 'Large'} df_all['Family_Size_Grouped'] = df_all['Family_Size'].map(family_map) df_all['Ticket_Frequency'] = df_all.groupby('Ticket')['Ticket'].transform('count') df_all['Title'] = df_all['Name'].str.split(', ', expand=True)[1].str.split('.', expand=True)[0] df_all['Is_Married'] = 0 df_all['Is_Married'].loc[df_all['Title'] == 'Mrs'] = 1 df_all['Title'] = df_all['Title'].replace(['Miss', 'Mrs','Ms', 'Mlle', 'Lady', 'Mme', 'the Countess', 'Dona'], 'Miss/Mrs/Ms') df_all['Title'] = df_all['Title'].replace(['Dr', 'Col', 'Major', 'Jonkheer', 'Capt', 'Sir', 'Don', 'Rev'], 'Dr/Military/Noble/Clergy') df_train = df_all.loc[:890] df_test = df_all.loc[891:] dfs = [df_train, df_test] non_numeric_features = ['Embarked', 'Sex', 'Title', 'Family_Size_Grouped', 'Age', 'Fare'] for df in dfs: for feature in non_numeric_features: df[feature] = LabelEncoder().fit_transform(df[feature]) cat_features = ['Pclass', 'Sex', 'Embarked', 'Title', 'Family_Size_Grouped'] encoded_features = [] for df in dfs: for feature in cat_features: encoded_feat = OneHotEncoder().fit_transform(df[feature].values.reshape(-1, 1)).toarray() n = df[feature].nunique() cols = ['{}_{}'.format(feature, n) for n in range(1, n + 1)] encoded_df = pd.DataFrame(encoded_feat, columns=cols) encoded_df.index = df.index encoded_features.append(encoded_df) df_train = pd.concat([df_train, *encoded_features[:5]], axis=1) df_test = pd.concat([df_test, *encoded_features[5:]], axis=1) df_all = concat_df(df_train, df_test) drop_cols = ['Cabin', 'Embarked', 'Family_Size', 'Family_Size_Grouped', 'Survived', 'Name', 'PassengerId', 'Pclass', 'Sex', 'Ticket', 'Title', 'Family_Size_Grouped_1', 'Family_Size_Grouped_2', 'Family_Size_Grouped_3', 'Family_Size_Grouped_4', 'Ticket_Frequency', 'Title_1', 'Title_2', 'Title_3', 'Title_4', 'Is_Married'] df_all.drop(columns=drop_cols, inplace=True) print(df_all.head()) X_train = StandardScaler().fit_transform(df_train.drop(columns=drop_cols)) y_train = df_train['Survived'].values X_test = StandardScaler().fit_transform(df_test.drop(columns=drop_cols)) print('X_train shape: {}'.format(X_train.shape)) print('y_train shape: {}'.format(y_train.shape)) print('X_test shape: {}'.format(X_test.shape))
.
Hasilnya adalah sebagai berikut :
.
Age Embarked_1 Embarked_2 Embarked_3 ... Pclass_3 Sex_1 Sex_2 SibSp
0 28 0.0 0.0 1.0 ... 1.0 0.0 1.0 1
1 52 1.0 0.0 0.0 ... 0.0 1.0 0.0 1
2 34 0.0 0.0 1.0 ... 1.0 1.0 0.0 0
3 48 0.0 0.0 1.0 ... 0.0 1.0 0.0 1
4 48 0.0 0.0 1.0 ... 1.0 0.0 1.0 0
[5 rows x 12 columns]
X_train shape: (891, 12)
y_train shape: (891,)
X_test shape: (418, 12)
.
Modelling tanpa hasil Feature Engineering – Part 2
Masukan perintah berikut
from sklearn.ensemble import RandomForestClassifier random_forest = RandomForestClassifier(criterion='gini', n_estimators=1100, max_depth=5, min_samples_split=4, min_samples_leaf=5, max_features='auto', oob_score=True, random_state=50) random_forest.fit(X_train, y_train)
.
from sklearn.model_selection import cross_val_score scores = cross_val_score(random_forest, X_train, y_train, cv=10, scoring = "accuracy") print("Scores:", scores) print("Mean:", scores.mean()) print("Standard Deviation:", scores.std())
.
dengan output
Akurasi yang diperoleh melalui pemodelan tanpa feature engineering adalah 0.81258. Nilai ini lebih rendah 0.02 atau 2% dari pemodelan dengan penggunaan feature engineering.
Ini artinya bahwa penggunaan feature engineering dapat menaikkan akurasi model. Karena, fitur turunan (fitur yang direkayasa) melalui teknik feature engineering ini memiliki dampak yang signifikan pada model yang dibangun. Denga kata lain, feature engineering merupakan hal yang terpenting dilakukan untuk meningkatkan performansi model machine learning.
Note: Akurasi ini tidak absolut dan dapat berubah, tergantung dari banyak factor, termasuk dari parameter yang dimasukkan. Fitur yang kita buat pun dapat menjadi buruk juga tergantung tipe model yang digunakan.
.
Kesimpulan
Hasil perbandingan dari 2 model tersebut seperti di bawah ini:
.
Konklusi :
Feature Engineering mengharuskan kita membuat banyak ide fitur dari data yang sudah ada. Biasanya yang dapat kita lakukan adalah, penggabungan (grouping), ekstraksi fitur (seperti Title yang didapat dari nama orang), dan masih banyak lagi.
Jangan malas untuk melakukan feature engineering dan mencoba segala sesuatu yang ada di pikiran kita. Barangkali ini dapat meningkatkan akurasi model kita.
.