Dilansir dari Investopedia, customer churn atau biasa dikenal sebagai atrisi pelanggan, adalah peristiwa dimana pelanggan tidak lagi melakukan bisnis dengan perusahaan atau berhenti dari pelayanan yang diberikan perusahaan. Biasanya, bentuk bisnis yang umum dijadikan ukuran adalah persentase pelanggan yang berhenti berlanggan (unsubscribe) suatu pelayanan tertentu selama rentang waktu yang telah ditentukan.
Sebagai pemilik bisnis, menaruh perhatian yang lebih untuk mempertahankan hubungan baik dengan pelanggan jauh lebih mudah daripada mencoba memperluas audiens untuk memperoleh pelanggan baru. Bahkan, mengakuisisi 1 pelanggan baru menghabiskan biaya 5 kali lipat daripada kita mempertahankan pelanggan lama. Karena itulah kesadaran terhadap tingkat artisi pelanggan menjadi sangat penting (Mailchimp).
Selain banyaknya pelanggan yang berhenti berlangganan, Customer churn juga bisa menandakan seberapa banyak pelanggan yang tidak lagi membuat pesanan baru dari bisnis kita. Customer churn memberikan gambaran terkait apa yang membuat pelanggan “keluar” dari bisnis yang kita lakukan. Setelah itu, dapat ditentukan solusi untuk mempertahankan pelanggan yang kita miliki saat ini.
Pada project kali ini, kita akan menggunakan dataset yang berisi informasi transaksi pelanggan di sebuah toko retail dari tahun 2013 sampai 2019. Kolom pada dataset terdiri dari ID Pelanggan (sebagai unique identifier), Produk yang dibeli oleh pelanggan tersebut, Tanggal pertama kali transaksi, Tanggal terakhir transaksi, Rata-rata jumlah transaksi yang dihabiskan (spending amount), dan Banyaknya transaksi yang telah dilakukan.
Sebagai data analyst, kita akan menggunakan data tersebut untuk mengidentifikasi pola pelanggan seperti apa yang berpotensi untuk tidak melakukan transaksi lagi. Untuk itu, akan diimplementasikan salah satu metode klasifikasi pada machine learning, yakni Regresi Logistik untuk memprediksi kira-kira pelanggan mana yang akan terklasifikasi sebagai pelanggan yang churn.
Setelah kita mengetahui tujuan yang mendasari proses analisis data dan juga kita telah meng-Obtain data. Berdasarkan OSEMN framework, yang harus dilakukan selanjutnya adalah Scrub atau membersihkan data atau biasa dikenal sebagai data cleaning / data preparation. Kemudian tahap Explore dengan memanfaatkan visualisasi grafik, tahap Modeling, dan tahap iNterpretasi
import pandas as pd
df = pd.read_csv('', sep=';')
df.shape
df.head()
df.info()
Selain mengimport dataset, kita juga perlu memeriksa ada berapa banyak daya yang akan kita olah, seperti apa tampilan data, juga informasi mengenai tipe data setiap kolom yang terbaca oleh python.
Ternyata, data kita terdiri dari 10000 amatan dan 8 kolom, namun disini terlihat bahwa terdapat kolom duplikasi yang sebenarnya informasi yang diberikan oleh kolom tersebut tidak begitu penting untuk analisis yang dilakukan, hal ini akan kita periksa kembali di tahapan data cleansing.
Selanjutnya, dari keluaran function info(), sebagian kolom dari dataset terbaca sebagai integer dan hanya satu kolom yang datanya bertipe object. Namun kita bisa melihat disini bahwa ada kolom yang sebenarnya harus berformat datetime, bukan integer, sehingga harus diubah terlebih dahulu.
Masih mengenai output function info(), ternyata tidak ada satu pun kolom di dataset df yang memiliki missing value sehingga dapat dikatakan bahwa data ini terbebas dari masalah missing value.
- Hapus Kolom No dan Rownum
Berdasarkan hasil inspeksi sebelumnya, kolom No dan Rownum adalah kolom dengan informasi yang serupa, dan keduanya sama-sama tidak memberikan informasi yang berguna baik dalam penggalian insight maupun model prediksi, Oleh karena itu, kedua kolom ini perlu dihapus dari data.
del df['no']
del df['Row_Num']
df.head()
Setelah melakukan perubahan pada data, seperti biasa periksa kembali tampilan data yang dihasilkan. Terlihat dari output di atas bahwa kolom No dan Rownum sudah tidak ada lagi pada dataset df.
2. Mengubah Tipe Data First_Transaction dan Last_Transaction
Setelah diperiksa kembali, 2 dari 8 kolom perlu diubah menjadi tipe data tanggal untuk memudahkan proses analisis berikutnya. Kolom tersebut adalah First_Transaction dan Last_Transaction yang memberian informasi mengenai kapan pertama kali dan terakhir kali seorang pelanggan melakukan transaksi di toko tersebut.
df['First_Transaction'] = pd.to_datetime(df['First_Transaction']/1000, unit='s', origin='1970-01-01')
df['Last_Transaction'] = pd.to_datetime(df['Last_Transaction']/1000, unit='s', origin='1970-01-01')
3. Pembentukan Kolom is_churn
Selain informasi dari 8 kolom yang sudah ada di dalam data, kita juga memerlukan kolom lain yang menandakan apakah seorang customer termasuk kategori churn atau bukan. Misal pada kasus ini, seorang customer sudah bukan disebut pelanggan lagi (churn) ketika dia sudah tidak bertransaksi ke tokonya sampai dengan 6 bulan terakhir dari update data terakhir yang tersedia.
Maka, hal pertama yang harus dilakukan adalah memeriksa kapan transaksi terakhir yang ada di dalam dataset. Untuk itu, digunakan perintah max seperti berikut.
print(max(df['Last_Transaction']))
Setelah kita mengetahui informasi transaksi terakhir yang terjadi pada tanggal 16 Februari 2019, selanjutnya adalah menentukan batasan tanggal transaksi yang menjadi kriteria seorang pelanggan termasuk kategori churn atau tidak. Karena toko ini memberi batasan 6 bulan, maka seorang customer termasuk kategori churn jika transaksi terakhirnya kurang dari 1 Agustus 2018.
Pemberian label churn atau tidak menggunakan boolean True/False pada kolom baru yang diberi nama is_churn
df.loc[df['Last_Transaction'] <= '2018-08-01','is_churn'] = True
df.loc[df['Last_Transaction'] >= '2018-08-01','is_churn'] = False
df.head()
Pada tahap ini, kita akan melakukan eksplorasi data melalui visualisasi. Dengan ini, kita bisa memperoleh informasi-informasi yang relevan dengan objektif analsisi data. Selain itu, kita juga mendapat insight-insight menarik yang bermanfaat.
- Graph of Customer Acquisition
Apa sih Customer Acquisition itu?
Dilansir dari Hubspot, akuisis pelanggan atau customer acquisition adalah proses mendapatkan pelanggan potensial untuk membeli produk kita. Kalau dihubungkan dengan data ini, metrik akuisisi pelanggan dapat dilihat dari banyaknya pelanggan yang melakukan transaksi pertama di setiap tahunnya.
Karena informasi tahun transaksi pertama belum tersedia, maka perlu dibuat terlebih dahulu kolom Year_First_Transaction. Sebagai tambahan, buat juga kolom Year_Last_Transaction yang menandakan tahun dari transaksi terakhir.
# Kolom tahun transaksi pertama
df['Year_First_Transaction'] = df['First_Transaction'].dt.year
# Kolom tahun transaksi terakhir
df['Year_Last_Transaction'] = df['Last_Transaction'].dt.year
Setelah itu, kelompokkan banyaknya pelanggan berdasarkan tahun ia melakukan transaksi pertama. Hasil pengelompokkan ini disimpan ke dalam variabel df_year
df_year = df.groupby(['Year_First_Transaction'])['Customer_ID'].count()
df_year ini terdiri dari dua kolom yang masing-masing berisi tahun transaksi pertama (dari 2013 sampai 2019) dan banyaknya pelanggan yang terakuisisi.
Untuk membuat grafik, perintah yang dijalankan adalah sebagai berikut
import matplotlib.pyplot as plt
df_year.plot(x='Year_First_Transaction', y='Num_of_Customers', kind='bar', title='Graph of Customer Acquisition')
plt.xlabel('Year_First_Transaction')
plt.ylabel('Num_of_Customers')
plt.tight_layout()
plt.show()
Dari grafik di atas, terlihat bahwa tren akuisis pelanggan setiap tahunnya mengalami kenaikan, kecuali sejak tahun 2018. Sejak itu, akuisis pelanggan menurun sedikit, hal ini bisa saja terjadi karena pada tahun 2018 upaya akuisisi pelanggan yang dilakukan tidak efektif, misal marketing effort yang dijalankan kurang bervariasi sehingga menurunkan minat calon pelanggan baru untuk membeli produk di toko ini.
2. Graph of Transaction Customer
Sama seperti sebelumnya, kita harus mengelompokkan banyaknya transaksi (kolom Count_Transaction) tiap tahun dan hasilnya disimpan ke dalam variabel df_count. Variabel inilah yang akan divisualisasikan dalam bentuk diagram batang. Perintah yang dijalanan adalah sebagai berikut.
df_count = df.groupby(['Year_First_Transaction'])['Count_Transaction'].sum()
df_count.plot(x='Year_First_Transaction', y='Count_Transaction', kind='bar', title='Graph of Transaction Customer')
plt.xlabel('Year_First_Transaction')
plt.ylabel('Num_of_Transaction')
plt.tight_layout()
plt.show()
Bisa dilihat bahwa banyaknya transaksi tidak menunjukkan pola tertentu. Namun terjadi penurunan drastis pada tahun 2018 mengingat kita juga tahu bahwa di tahun 2018, jumlah pelanggan yang melakukan transaksi pertama juga menurun.
3. Average Transaction Per Product
Visualisasi ketiga adalah rata-rata jumlah transaksi (Average_Transaction_Amount) per tahun untuk setiap produk yang dibeli. plot garis ini dibuat untuk melihat tren pembelian dari setiap produk supaya kita mengetahui produk apa yang paling digemari setiap tahunnya, dan produk apa yang kurang diminati.
Data yang akan divisualisasikan adalah data hasil pengelompokkan rata-rata transaksi berdasarkan tahun transaksi pertama dan produk yang dibeli. grafik yang dibuat adalah pointplot yang terdapat pada seaborn. Perintah yang dijalankan adalah sebagai berikut.
import seaborn as sns
sns.pointplot(data = df.groupby(['Product','Year_First_Transaction']).mean().reset_index(),
x='Year_First_Transaction',
y='Average_Transaction_Amount',
hue='Product')
plt.tight_layout()
plt.show()
Produk baju dan tas baru diluncurkan pada tahun 2017, keduanya menunjukkan tren yang naik. Meskipun di tahun 2019 ada penurunan, namun mengingat transaksi terakhir yang tercatat pada dataset masih di bulan Februari, maka ada kemungkinan keseluruhan rata-rata transaksi untuk kedua produk ini akan terus meningkat.
Untuk produk sepatu yang sudah dari tahun 2013, memilik tren yang cenderung stabil namun lagi-lagi di tahun 2018 mengalami penurunan. Sebaliknya, pada tahun 2018, produk jaket tidak mengalami penurunan. Bahkan sejak tahun 2015, rata-rata transaksi jaket konsisten naik walaupun nilai paling tingginya belum bisa melampaui tahun 2014, tahun dimana jaket diluncurkan.
4. Customer Churn Proportion per Product
Selanjutnya, kita akan melihat proporsi pelanggan yang churn di setiap produk dengan diagram lingkaran. Dari grafik ini kita bisa memperoleh informasi mengenai produk apa yang berpotensi menghasilkan customer churn yang paling banyak sebagai bahan evaluasi untuk tim produk tersebut.
Hal pertama yang harus dilakukan adalah pivot data berdasarkan banyaknya pelanggan yang masuk kategori churn di setiap produk. Hasilnya berupa tabel pivot yang meringkas informasi yang dibutuhkan.
Argumen yang dibutuhkan pada function pivot_table kurang lebih sama seperti pivot table pada spreadsheet, dimana kita harus menspesifikasikan kolom yang ingin diringkas (values), kolom yang menjadi acuan pengelompokkan(index), dan fungsi agregat apa yang akan ditampilkan (aggfunc).
df_piv = df.pivot_table(index='is_churn',
columns='Product',
values='Customer_ID',
aggfunc='count',
fill_value=0)
df_piv
Selanjutnya, membuat diagram lingkaran untuk memvisualisasikan hasil tabel pivot di atas.
df_piv.plot.pie(subplots=True,
figsize=(10, 7),
layout=(-1, 2),
autopct='%1.0f%%',
title='Proportion Churn by Product')
plt.tight_layout()
plt.show()
Melalui diagram lingkaran di atas, kita dapat memperoleh informasi bahwa tas adalah produk dengan proporsi customer churn paling rendah, sementara jaket adalah produk dengan proporsi customer churn paling tinggi.
Customer churn yang tinggi pada produk jaket berhubungan dengan rata-rata total transaksi yang nilainya belum dapat melampaui tahun pertama. Hal ini bisa saja terjadi ketika produk jaket yang ditawarkan mengalami penurunan kualitas yang menyebabkan pelanggan tidak berminat untuk membeli jaket lagi. Untuk itu, tim produk jaket perlu melakukan peninjauan ulang untuk memastikan bahwa kualitas jaket yang ditawarkan memiliki kualitas yang sama bahkan lebih baik daripada ketika jaket baru diluncurkan di pasaran.
Kita telah memiliki kolom is_churn yang merupakan kolom dengan tipe data kategorik true or false yang menandakan seorang customer termasuk kategori churn atau tidak. Karena target variable yang dimiliki adalah data kategorik, maka salah satu metode klasifikasi dalam machine learning yang bisa digunakan adalah regresi logistik.
Apa itu regresi logistik?
Dilansir dari Towardsdatascience, regresi logistk adalah algoritma klasifikasi machine learning yang digunakan untk memprediksi peluang variabel target bertipe kategorik. Regresi logistik memprediksi P(Y=1) sebagai fungsi dari satu atau beberapa peubah penjelas X.
Pada kasus ini, tidak semua kolom dijadikan peubah penjelas atau feature variable, hanya kolom Average_Transaction_Amount, Count_Transaction, dan Year_Diff yang menjadi prediktor untuk variabel target. Karena kolom Year_Diff belum ada di dalam dataset, maka perlu dibuat terlebih dahulu dengan menghitung selisih dari tahun transaksi terakhir dengan tahun transaksi pertama lalu di assign ke dalam dataset.
Setelah itu, definisikan x dan y menggunakan perintah di bawah ini.
df['Year_Diff'] = df['Year_Last_Transaction'] - df['Year_First_Transaction']# Nama-nama feature columns
feature_columns = ['Average_Transaction_Amount', 'Count_Transaction', 'Year_Diff']
# Features variable
X = df[feature_columns]
# Target variable
y = df['is_churn']
Sebagai tahap awal pada algoritma machine learning, kita perlu membagi data menjadi set training dan testing pada x dan y. data training dimaksudkan untuk “melatih” mesin melalui data yang sudah kita miliki untuk mengukur seberapa baik model yang dihasilkan sesuai dengan data yang ada. Sedangkan data testing untuk menguji apakah model hasil training tadi berhasil mengklasifikasi data yang belum dilihat sebelumnya dan seberapa baik tingkat akurasi modelnya.
Penentuan proporsi pembagian data sepenuhnya didasarkan pada peneliti, biasanya 20 sampai 30 persen, kali ini, kita akan membagi 25% dari data sebagai data testing. Pembagian data ini dapat dijalankan dengan perintah berikut.
from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state=1)
Setelah itu, kita memfit model regresi logistik pada data training. Kemudian kita memprediksi data testing menggunakan model yang sudah dibangun oleh algoritma regresi logistik ini. Evaluasi keakuratan model bisa dilihat menggunakan confussion matrix, nilai accuracy, precission dan recall.
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix# Inisiasi model logreg
logreg = LogisticRegression()
# fit the model with data
logreg.fit(X_train, y_train)
# Predict model
y_pred = logreg.predict(X_test)
y_pred adalah hasil klasifikasi churn atau tidak berdasarkan data testing dari peubah penjelas. Untuk mengukur keakuratan model, hasil klasifisikasi model (y_pred) ini akan dibandingkan dengan data testing dari variabel target (y_test).
Setelah memfitting model dan membuat prediksi, langkah selanjutnya adalah mengevaluasi performa model. Metrik pertama yang digunakan adalah confussion matrix.
Mengutip dari Sciencedirect, confussion matrix memvisualisasikan dan meringkas performa algoritma klasifikasi. Confussin matrix ini memiliki empat elemen, yakni True Positive (Kondisi sebenarnya bernilai 1 dan terklasifikasi oleh model sebagai 1), False Positive (Kondisi sebenarnya bernilai 0 dan terklasifikasi oleh model sebagai 1), False Negative (Sebenarnya 1 terklasifikasi sebagai 0), dan True Negative (Sebenarnya 0 terklasifikasi sebagai 0).
Dalam kasus ini, keadaan 1 adalah kelompok pelanggan yang termasuk churn dan keadaan 0 adalah kelompok yang bukan churn. Sebagai peneliti, tentu yang kita inginkan semua data testing masuk ke dalam True Positive atau True Negative.
Namun hal ini jarang sekali terjadi karena model yang dibuat tidak selalu benar. Ingat satu kalimat paling terkenal dalam statistika,
“All models are wrong, but some are useful” — Goerge Box
Karena itulah, ekspektasi kita berubah sedikit menjadi data yang termasuk True Positive dan True Negative memiliki jumlah yang lebih banyak daripada False Positive dan False Negative. (Memaksimumkan data yang terklasifikasi dengan benar dan membuat data yang salah terklasifikasi menjadi sesedikit mungkin).
Untuk membentuk confusion matrix di python bisa menggunakan perintah berikut
cnf_matrix = confusion_matrix(y_test, y_pred)
cnf_matrix
Kita juga bisa membuat confussion matrix menjadi bentuk heatmap dengan perintah berikut
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns# name of classes
class_names = [0, 1]
fig, ax = plt.subplots()
tick_marks = np.arange(len(class_names))
plt.xticks(tick_marks, class_names)
plt.yticks(tick_marks, class_names)
# create heatmap
sns.heatmap(pd.DataFrame(cnf_matrix), annot=True, cmap='YlGnBu', fmt='g')
ax.xaxis.set_label_position('top')
plt.title('Confusion Matrix', y=1.1)
plt.ylabel('Actual')
plt.xlabel('Predicted')
plt.tight_layout()
plt.show()
Dari confussion matrix tersebut bisa dilihat lebih dari 16 ribu data terklasifikasi sebagai True Positive namun hanya 1 data yang True Negative. Terdapat lebih dari 8 ribu data yang sebenarnya bukan churn (0) tapi diklasifikasikan sebagai churn (1) oleh model.
Ini memang bukan hasil yang diharapkan, hal ini menandakan adanya overfitting, model cenderung lebih mengklasifikasikan data menjadi kategori churn. Bias seperti ini wajar terjadi lantaran pembagian data training dan testing dilakukan secara acak, kita tidak bisa memastikan bahwa proporsi churn dan bukan churn adalah sama di setiap bagian.
Pada kasus ini, bisa saja model training lebih banyak mengandung data yang termasuk kategori churn sehingga ketika model digunakan untuk memprediksi data yang sebenarnya bukan churn, model ini cenderung mengklasifikasikannya sebagai churn.
Metrik evaluasi lainnya adalah accuracy, prediction, dan recall
from sklearn.metrics import accuracy_score, precision_score, recall_score#Menghitung Accuracy, Precision, dan Recall
print('Accuracy :', accuracy_score(y_test, y_pred))
print('Precision:', precision_score(y_test, y_pred, average='micro'))
print('Recall :', recall_score(y_test, y_pred, average='micro'))
Accuracy adalah rasio banyaknya data yang terklasifikasi dengan benar dan total semua data
Precision means what percentage of the positive predictions made were actually correct — towardsdatascience
Sederhananya, precision menjawab pertanyaan berupa, dari semua pelanggan yang terklasifikasi sebagai churn, berapa banyak dari mereka yang benar-benar churn?
Recall means what percentage of actual positive predictions were correctly classified by the classifier — towardsdatascience
Simpelnya, recall adalah kebalikan dari precision. Recall menjawab pertanyaan berupa, Dari semua pelanggan yang benar-benar churn, berapa banyak dari mereka yang terklasifikasi oleh model sebagai churn
Dari data di atas, hasil akurasi, presisi, dan recall memiliki nilai yang sama, yaitu 0.66532