<jupyter_start><jupyter_text>**Author: <NAME> (<EMAIL>) - December 24, 2020**  Data Science in Telco: Data Cleansing Data Mentor pada topik ini adalah Ant<NAME>, Data Scientist di Telkom Indonesia. **Deskripsi**: DQLab Telco merupakan perusahaan Telco yang sudah mempunyai banyak cabang tersebar dimana-mana. Sejak berdiri pada tahun 2019, DQLab Telco konsisten untuk memperhatikan *customer experience*nya sehingga tidak akan ditinggalkan pelanggan.Walaupun baru berumur 1 tahun lebih sedikit, DQLab Telco sudah mempunyai banyak pelanggan yang beralih langganan ke kompetitior. Pihak managemen ingin mengurangi jumlah pelanggan yang beralih (churn) dengan menggunakan machine learning.Oleh karena itu, tim Data Scientist diminta untuk mempersiapkan data sekaligus membuat model prediksi yang tepat untuk menentukan pelanggan akan berhenti berlangganan (churn) atau tidak. **Tugas**: Sebagai seorang data scientist, kamu diminta untuk menyiapkan data sebelum di lakukan permodelan. Pada tugas kali ini, kamu akan melakukan *Data Prepocessing* bulan lalu, yakni Juni 2020.Langkah yang akan dilakukan adalah sebagai berikut:- Mencari ID pelanggan yang valid- Mengatasi data-data yang masih kosong (*Missing Values*)- Mengatasi *outlier* dari setiap variabel- Menstandarisasi nilai dari variabel  Package dan Libraries **Pandas** Pandas adalah library Python yang fokus untuk proses analisis data seperti manipulasi data, persiapan data, dan pembersihan data.            - read_csv() digunakan untuk membaca file csv- str.match() digunakan untuk mencocokan dengan karakter tertentu- drop() digunakan untuk menghapus- count() digunakan untuk mengitung masing-masing variable- drop_duplicates() digunakan untuk menghapus data duplicate rows- fillna() digunakan untuk mengisi dengan nilai tertentu- quantile() digunakan untuk melihat quantile ke tertentu- mask() menganti nilai tertentu jika kondisi memenuhi- astype() merunubah tipe data- value_counts() digunakan untuk mengitung unik dari kolom- sort_values() digunakan untuk sort values- isnull() digunakan untuk mendeteksi missing values- dropna() digunakan untuk menghapus missing values- replace() digunakan untuk mengganti nilai  **Matplotlib** Matplotlib adalah library Python yang fokus pada visualisasi data seperti membuat plot grafik. Matplotlib dapat digunakan dalam skrip Python, Python dan IPython shell, server aplikasi web, dan beberapa toolkit graphical user interface (GUI) lainnya.- figure() digunakan untuk membuat figure gambar baru **Seaborn** Seaborn membangun di atas Matplotlib dan memperkenalkan tipe plot tambahan. Ini juga membuat plot Matplotlib tradisional Anda terlihat sedikit lebih cantik.- box_plot() digunakan untuk membuat box plot  Import Dataset<jupyter_code># import library
import pandas as pd
pd.options.display.max_columns = 50<jupyter_output><empty_output><jupyter_text>**pd.options.display.max_columns = 50** digunakan untuk mengatur jumlah kolom maksimum yang ditampilkan.<jupyter_code># import dataset
telco = pd.read_csv('dqlab_telco.csv')
print('Dataset Size', telco.shape)
telco.head()<jupyter_output>Dataset Size (7113, 22)<jupyter_text>Keterangan:- UpdatedAt : Periode of Data taken- customerID : Customer ID- gender : Whether the customer is a male or a female (Male, Female)- SeniorCitizen : Whether the customer is a senior citizen or not (1, 0)- Partner : Whether the customer has a partner or not (Yes, No)- Dependents : Whether the customer has dependents or not (Yes, No)- tenure : Number of months the customer has stayed with the company- PhoneService : Whether the customer has a phone service or not (Yes, No)- MultipleLines : Whether the customer has multiple lines or not (Yes, No, No phone service)- InternetService : Customer’s internet service provider (DSL, Fiber optic, No)- OnlineSecurity : Whether the customer has online security or not (Yes, No, No internet service)- OnlineBackup : Whether the customer has online backup or not (Yes, No, No internet service)- DeviceProtection : Whether the customer has device protection or not (Yes, No, No internet service)- TechSupport : Whether the customer has tech support or not (Yes, No, No internet service)- StreamingTV : Whether the customer has streaming TV or not (Yes, No, No internet service)- StreamingMovies : Whether the customer has streaming movies or not (Yes, No, No internet service)- Contract : The contract term of the customer (Month-to-month, One year, Two year)- PaperlessBilling : Whether the customer has paperless billing or not (Yes, No)- PaymentMethod : The customer’s payment method (Electronic check, Mailed check, Bank transfer (automatic), Credit card (automatic))- MonthlyCharges : The amount charged to the customer monthly- TotalCharges : The total amount charged to the customer- Churn Whether : The customer churned or not (Yes or No)<jupyter_code># number of unique IDs
print(telco.customerID.nunique())<jupyter_output>7017<jupyter_text>Mencari Validitas ID Number Pelanggan  Memfilter ID Number Pelanggan dengan Format Tertentu Mencari format 'customerID' yang benar, dengan kriteria:- Panjang karakter adalah 11-12- Terdiri dari angka saja, tidak diperbolehkan ada karakter selain angka- Diawali dengan angka 45 pada 2 digit pertama<jupyter_code>telco['valid_id'] = telco['customerID'].astype(str).str.match(r'(45\d{9,10})')
telco = (telco[telco['valid_id'] == True]).drop('valid_id', axis = 1)<jupyter_output><empty_output><jupyter_text>**str.match()** dan **regex** digunakan untuk mencocokan dengan kriteria yang diberikan.<jupyter_code>print('Hasil filter jumlah ID Customer adalah',telco['customerID'].count())<jupyter_output>Hasil filter jumlah ID Customer adalah 7006<jupyter_text>Memfilter Duplikasi ID Number Pelanggan Memastikan bahwa tidak ada 'customerID' yang duplikat. Duplikasi 'customerID' dapat terjadi karena hal berikut:- Duplikasi dikarenakan inserting melebihi satu kali dengan nilai yang sama tiap kolomnya- Duplikasi dikarenakan inserting beda periode pengambilan data<jupyter_code>print('Dataset Size', telco.shape)
telco.duplicated().sum()<jupyter_output>Dataset Size (7006, 22)<jupyter_text>Terdapat 7 duplikasi pada dataset.<jupyter_code># drop duplicate rows
telco.drop_duplicates()

# drop duplicate customerID sorted by UpdatedAt
telco = telco.sort_values('UpdatedAt', ascending=False).drop_duplicates(['customerID'])
print('Hasil jumlah ID Customer yang sudah dihilangkan duplikasinya adalah',telco['customerID'].count())<jupyter_output>Hasil jumlah ID Customer yang sudah dihilangkan duplikasinya adalah 6993<jupyter_text>Kesimpulan Validitas dari ID Number pelanggan sangat diperlukan untuk memastikan bahwa data yang diambil sudah benar. Berdasarkan hasil tersebut, terdapat perbedaan jumlah nomor ID dari data pertama kali di*load* sampai dengan hasil akhir. Jumlah *row* data ketika pertama kali di*load* ada sebanyak 7113 *rows* dan 22 *columns* dengan 7017 jumlah ID yang unik. Kemudian, setelah dicek validitas dari ID pelanggan, maka tersisa 6993 *rows* data.  Mengatasi Missing Values  Mengatasi Missing Values dengan Penghapusan Rows Selanjutnya akan dihapus *rows* dari data yang tidak terdeteksi apakah dia churn atau tidak. Diasumsikan data modeller hanya mau menerima data yang terdapat status churn-nya.<jupyter_code>print('Total missing values data dari kolom Churn',telco['Churn'].isnull().sum())
# dropping all rows with spesific column (churn)
telco.dropna(subset=['Churn'],inplace=True)
print('Total rows dan kolom data setelah dihapus missing values adalah',telco.shape)<jupyter_output>Total rows dan kolom data setelah dihapus missing values adalah (6950, 22)<jupyter_text>Mengatasi Missing Values dengan Pengisian Nilai tertentu Selain dengan mengapus *rows* dari data, menangani *missing values* bisa menggunakan nilai tertentu. Diasumsikan data modeller meminta pengisian *missing values* dengan kriteria berikut:- Pihak data modeller meminta setiap *rows* yang memiliki *missing values* untuk 'Tenure' diisi dengan 11- Variable yang bersifat numerik selain 'Tenure' diisi dengan median dari masing-masing variabel tersebut<jupyter_code>print('Status Missing Values :',telco.isnull().values.any())
print('\nJumlah Missing Values masing-masing kolom, adalah:')
print(telco.isnull().sum().sort_values(ascending=False))
# handling missing values Tenure fill with 11
telco['tenure'].fillna(11, inplace=True)

# handling missing values numeric vars (except Tenure)
for col_name in list(['MonthlyCharges','TotalCharges']):
    median = telco[col_name].median()
    telco[col_name].fillna(median, inplace=True)
print('\nJumlah Missing Values setelah di imputer datanya, adalah:')
print(telco.isnull().sum().sort_values(ascending=False))<jupyter_output>Jumlah Missing Values setelah di imputer datanya, adalah:
Churn               0
TotalCharges        0
customerID          0
gender              0
SeniorCitizen       0
Partner             0
Dependents          0
tenure              0
PhoneService        0
MultipleLines       0
InternetService     0
OnlineSecurity      0
OnlineBackup        0
DeviceProtection    0
TechSupport         0
StreamingTV         0
StreamingMovies     0
Contract            0
PaperlessBilling    0
PaymentMethod       0
MonthlyCharges      0
UpdatedAt           0
dtype: int64<jupyter_text>Kesimpulan Setelah analisis lebih lanjut, ternyata masih ada *missing values* dari data yang sudah valid ID Number pelanggannya. *Missing values* terdapat pada kolom 'Churn', 'Tenure', 'MonthlyCharges' dan 'TotalCharges'. Setelah ditangani dengan cara penghapusan *rows* dan pengisian *rows* dengan nilai tertentu, maka sudah tidak ada *missing value*s lagi pada data, terbukti dari jumlah *missing values* masing-masing variabel yang bernilai 0.  Mengatasi Outlier  Mendeteksi adanya Outlier dengan Boxplot Mendeteksi *outlier* dapat dilihat dengan menggunakan Box Plot. Boxplot merupakan ringkasan distribusi sampel yang disajikan secara grafis yang bisa menggambarkan bentuk distribusi data (*skewness*), ukuran tendensi sentral dan ukuran penyebaran (keragaman) data pengamatan.<jupyter_code>print('\nPersebaran data sebelum outlier ditangani: ')
print(telco[['tenure','MonthlyCharges','TotalCharges']].describe())

# creating Box Plot
import matplotlib.pyplot as plt
import seaborn as sns

plt.figure() # untuk membuat figure baru
sns.boxplot(x=telco['tenure'])
plt.show()

plt.figure() # untuk membuat figure baru
sns.boxplot(x=telco['MonthlyCharges'])
plt.show()

plt.figure() # untuk membuat figure baru
sns.boxplot(x=telco['TotalCharges'])
plt.show()<jupyter_output>Persebaran data sebelum outlier ditangani: 
            tenure  MonthlyCharges  TotalCharges
count  6950.000000     6950.000000   6950.000000
mean     32.477266       65.783741   2305.083460
std      25.188910       50.457871   2578.651143
min       0.000000        0.000000     19.000000
25%       9.000000       36.462500    406.975000
50%      29.000000       70.450000   1400.850000
75%      55.000000       89.850000   3799.837500
max     500.000000     2311.000000  80000.000000<jupyter_text>Mengatasi Outlier Setelah diketahui variabel mana saja yang terdapat *outlier*, selanjutnya *outlier* akan atasi dengan menggunakan metode *interquartile range* (IQR).<jupyter_code># handling with IQR
Q1 = (telco[['tenure','MonthlyCharges','TotalCharges']]).quantile(0.25)
Q3 = (telco[['tenure','MonthlyCharges','TotalCharges']]).quantile(0.75)
IQR = Q3 - Q1

maximum = Q3 + (1.5*IQR)
print('Nilai maximum dari masing-masing variabel adalah: ')
print(maximum)
minimum = Q1 - (1.5*IQR)
print('\nNilai minimum dari masing-masing variabel adalah: ')
print(minimum)

more_than = (telco > maximum)
lower_than = (telco < minimum)
telco = telco.mask(more_than, maximum, axis=1)
telco = telco.mask(lower_than, minimum, axis=1)
print('\nPersebaran data setelah outlier ditangani: ')
print(telco[['tenure','MonthlyCharges','TotalCharges']].describe())<jupyter_output>Nilai maximum dari masing-masing variabel adalah: 
tenure             124.00000
MonthlyCharges     169.93125
TotalCharges      8889.13125
dtype: float64

Nilai minimum dari masing-masing variabel adalah: 
tenure             -60.00000
MonthlyCharges     -43.61875
TotalCharges     -4682.31875
dtype: float64

Persebaran data setelah outlier ditangani: 
            tenure  MonthlyCharges  TotalCharges
count  6950.000000     6950.000000   6950.000000
mean     32.423165       64.992201   2286.058750
std      24.581073       30.032040   2265.702553
min       0.000000        0.000000     19.000000
25%       9.000000       36.462500    406.975000
50%      29.000000       70.450000   1400.850000
75%      55.000000       89.850000   3799.837500
max     124.000000      169.931250   8889.131250<jupyter_text>Kesimpulan Dari ketiga boxplot variabel 'tenure', 'MonthlyCharges' dan 'TotalCharges' terlihat jelas bahwa adanya *outlier*. Hal ini bisa diidentifikasi dari adanya titik titik yang berada jauh dari batas minimum atau maksimum boxplotnya.Kemudian nilai *outlier* tersebut ditangani dengan cara merubah nilai yang ekstrem ke nilai maksimum dan minimum dari *interquartile range* (IQR).  Menstandarisasi Nilai  Mendeteksi Nilai yang Tidak Standar Mendeteksi apakah terdapat nilai-nilai dari variabel kategorik yang tidak standar. Hal ini biasanya terjadi dikarenakan kesalahan input data, perbedaan istilah menjadi salah satu faktor yang sering terjadi. Oleh karena itu, dibutuhkan standarisasi dari data yang sudah terinput.<jupyter_code>for col_name in list(['gender','SeniorCitizen','Partner','Dependents','PhoneService','MultipleLines','InternetService','OnlineSecurity','OnlineBackup','DeviceProtection','TechSupport','StreamingTV','StreamingMovies','Contract','PaperlessBilling','PaymentMethod','Churn']):
    print('\nUnique Values Count \033[1m' + 'Before Standardized \033[0m Variable',col_name)
    print(telco[col_name].value_counts())<jupyter_output>Unique Values Count [1mBefore Standardized [0m Variable gender
Male         3499
Female       3431
Wanita         14
Laki-Laki       6
Name: gender, dtype: int64

Unique Values Count [1mBefore Standardized [0m Variable SeniorCitizen
0    5822
1    1128
Name: SeniorCitizen, dtype: int64

Unique Values Count [1mBefore Standardized [0m Variable Partner
No     3591
Yes    3359
Name: Partner, dtype: int64

Unique Values Count [1mBefore Standardized [0m Variable Dependents
No     4870
Yes    2060
Iya      20
Name: Dependents, dtype: int64

Unique Values Count [1mBefore Standardized [0m Variable PhoneService
Yes    6281
No      669
Name: PhoneService, dtype: int64

Unique Values Count [1mBefore Standardized [0m Variable MultipleLines
No                  3346
Yes                 2935
No phone service     669
Name: MultipleLines, dtype: int64

Unique Values Count [1mBefore Standardized [0m Variable InternetService
Fiber optic    3057
DSL            2388
No             1505
Name: [...]<jupyter_text>Menstandarisasi Variabel Kategorik Setelah diketahui variabel mana saja yang terdapat nilai yang tidak standar. Selanjutnya, akan distandarisasi dengan pola terbanyak-nya, dengan syarat tanpa mengubah maknanya. Contoh: Iya -> Yes Kemudian liat kembali unique values dari masing-masing variabel yang sudah di ubah.<jupyter_code>telco = telco.replace(['Wanita','Laki-Laki','Churn','Iya'],['Female','Male','Yes','Yes'])

for col_name in list(['gender','Dependents','Churn']):
    print('\nUnique Values Count \033[1m' + 'After Standardized \033[0mVariable',col_name)
    print(telco[col_name].value_counts())<jupyter_output>Unique Values Count [1mAfter Standardized [0mVariable gender
Male      3505
Female    3445
Name: gender, dtype: int64

Unique Values Count [1mAfter Standardized [0mVariable Dependents
No     4870
Yes    2080
Name: Dependents, dtype: int64

Unique Values Count [1mAfter Standardized [0mVariable Churn
No     5114
Yes    1836
Name: Churn, dtype: int64
{'fraction_non_alphanumeric': 0.07768949426157144, 'fraction_numerical': 0.047736158405851936, 'mean_word_length': 4.986787466968668, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '462167', 'license': 'MIT', 'n_tokens_mistral': 5969, 'n_tokens_neox': 5228, 'n_words': 1677, 'path': 'Data Cleansing.ipynb', 'repo_name': 'fitria-dwi/personal-notebook', 'size': '15892'}