Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Project: Default
Views: 1480
Kernel: Python 3 (Ubuntu Linux)

Визуальный анализ данных

Подключаем необходимые библиотеки.

import numpy as np import scipy as sp import pandas as pd import matplotlib.pyplot as plt %matplotlib inline import seaborn as sns

Считываем датасет.

data = pd.read_csv("telecom-churn.csv")

Проверяем, всё ли правильно считалось и "распарсилось".

data.head()
state account length area code phone number international plan voice mail plan number vmail messages total day minutes total day calls total day charge ... total eve calls total eve charge total night minutes total night calls total night charge total intl minutes total intl calls total intl charge customer service calls churn
0 KS 128 415 382-4657 no yes 25 265.1 110 45.07 ... 99 16.78 244.7 91 11.01 10.0 3 2.70 1 False
1 OH 107 415 371-7191 no yes 26 161.6 123 27.47 ... 103 16.62 254.4 103 11.45 13.7 3 3.70 1 False
2 NJ 137 415 358-1921 no no 0 243.4 114 41.38 ... 110 10.30 162.6 104 7.32 12.2 5 3.29 0 False
3 OH 84 408 375-9999 yes no 0 299.4 71 50.90 ... 88 5.26 196.9 89 8.86 6.6 7 1.78 2 False
4 OK 75 415 330-6626 yes no 0 166.7 113 28.34 ... 122 12.61 186.9 121 8.41 10.1 3 2.73 3 False

5 rows × 21 columns

Можно получить сводку и общее представление о типах данных.

data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 3333 entries, 0 to 3332 Data columns (total 21 columns): state 3333 non-null object account length 3333 non-null int64 area code 3333 non-null int64 phone number 3333 non-null object international plan 3333 non-null object voice mail plan 3333 non-null object number vmail messages 3333 non-null int64 total day minutes 3333 non-null float64 total day calls 3333 non-null int64 total day charge 3333 non-null float64 total eve minutes 3333 non-null float64 total eve calls 3333 non-null int64 total eve charge 3333 non-null float64 total night minutes 3333 non-null float64 total night calls 3333 non-null int64 total night charge 3333 non-null float64 total intl minutes 3333 non-null float64 total intl calls 3333 non-null int64 total intl charge 3333 non-null float64 customer service calls 3333 non-null int64 churn 3333 non-null bool dtypes: bool(1), float64(8), int64(8), object(4) memory usage: 524.1+ KB

Целевая переменная: churn (лояльность абонента). Это категориальный (более конкретно — бинарный) признак. Попробуем узнать, как распределены его значения.

data['churn'].value_counts()
False 2850 True 483 Name: churn, dtype: int64

Видим, что 2850 из 3333 абонентов — лояльные. А сколько это в процентах?..

data['churn'].value_counts(normalize=True)
False 0.855086 True 0.144914 Name: churn, dtype: float64

Визуализируем это.

data['churn'].value_counts(normalize=True).plot(kind='bar', title='Признак churn');
Image in a Jupyter notebook

Нам также может быть интересно, у скольких наших клиентов подключён роуминг.

data['international plan'].value_counts(normalize=True).plot(kind='bar');
Image in a Jupyter notebook

А как обстоят дела у нелояльных пользователей (churn=1)?

churn_users = data[data['churn'] == True] churn_users['international plan'].value_counts(normalize=True).plot(kind='bar');
Image in a Jupyter notebook

Видим, что процент клиентов с роумингом выше, чем в общей выборке.

Можем предположить, что бинарные признаки international plan и churn коррелируют. Нарисуем теперь их вместе.

pd.crosstab(data['churn'], data['international plan'], margins=True)
international plan no yes All
churn
False 2664 186 2850
True 346 137 483
All 3010 323 3333
sns.countplot(x='international plan', hue='churn', data=data);
Image in a Jupyter notebook

Большинство клиентов, у которых был подключён роуминг, от нас ушли!

data.groupby('international plan')['churn'].count()
international plan no 3010 yes 323 Name: churn, dtype: int64

Посмотрим на распределение признака account length.

sns.distplot(data['account length']);
Image in a Jupyter notebook

Похоже на нормальное распределение!

Что можно сказать о связи между account length и лояльностью?

data.groupby('churn')['account length'].mean()
churn False 100.793684 True 102.664596 Name: account length, dtype: float64
data.groupby('churn')['account length'].std()
churn False 39.88235 True 39.46782 Name: account length, dtype: float64
data.groupby('churn')['account length'].median()
churn False 100 True 103 Name: account length, dtype: int64

На первый взгляд, никак не связаны.

fig, ax = plt.subplots(1, 2, sharey=True) sns.distplot(data[data['churn'] == False]['account length'], ax=ax[0]).set_title('Лояльные'); sns.distplot(churn_users['account length'], ax=ax[1]).set_title('Ушедшие');
Image in a Jupyter notebook

На второй взгляд тоже.

Теперь посмотрим, связаны ли длительности дневных и ночных звонков.

sns.regplot(data['total day minutes'], data['total night minutes']);
Image in a Jupyter notebook

А как насчёт количества звонков?

sns.regplot(data['total day calls'], data['total night calls']);
Image in a Jupyter notebook

Пока никакой связи не видно.

Построим корреляционную матрицу для числовых признаков.

numeric_data = data.select_dtypes(['int64', 'float64'])
numeric_data.head()
account length area code number vmail messages total day minutes total day calls total day charge total eve minutes total eve calls total eve charge total night minutes total night calls total night charge total intl minutes total intl calls total intl charge customer service calls
0 128 415 25 265.1 110 45.07 197.4 99 16.78 244.7 91 11.01 10.0 3 2.70 1
1 107 415 26 161.6 123 27.47 195.5 103 16.62 254.4 103 11.45 13.7 3 3.70 1
2 137 415 0 243.4 114 41.38 121.2 110 10.30 162.6 104 7.32 12.2 5 3.29 0
3 84 408 0 299.4 71 50.90 61.9 88 5.26 196.9 89 8.86 6.6 7 1.78 2
4 75 415 0 166.7 113 28.34 148.3 122 12.61 186.9 121 8.41 10.1 3 2.73 3
corr_matrix = numeric_data.drop('area code', axis=1).corr() corr_matrix
account length number vmail messages total day minutes total day calls total day charge total eve minutes total eve calls total eve charge total night minutes total night calls total night charge total intl minutes total intl calls total intl charge customer service calls
account length 1.000000 -0.004628 0.006216 0.038470 0.006214 -0.006757 0.019260 -0.006745 -0.008955 -0.013176 -0.008960 0.009514 0.020661 0.009546 -0.003796
number vmail messages -0.004628 1.000000 0.000778 -0.009548 0.000776 0.017562 -0.005864 0.017578 0.007681 0.007123 0.007663 0.002856 0.013957 0.002884 -0.013263
total day minutes 0.006216 0.000778 1.000000 0.006750 1.000000 0.007043 0.015769 0.007029 0.004323 0.022972 0.004300 -0.010155 0.008033 -0.010092 -0.013423
total day calls 0.038470 -0.009548 0.006750 1.000000 0.006753 -0.021451 0.006462 -0.021449 0.022938 -0.019557 0.022927 0.021565 0.004574 0.021666 -0.018942
total day charge 0.006214 0.000776 1.000000 0.006753 1.000000 0.007050 0.015769 0.007036 0.004324 0.022972 0.004301 -0.010157 0.008032 -0.010094 -0.013427
total eve minutes -0.006757 0.017562 0.007043 -0.021451 0.007050 1.000000 -0.011430 1.000000 -0.012584 0.007586 -0.012593 -0.011035 0.002541 -0.011067 -0.012985
total eve calls 0.019260 -0.005864 0.015769 0.006462 0.015769 -0.011430 1.000000 -0.011423 -0.002093 0.007710 -0.002056 0.008703 0.017434 0.008674 0.002423
total eve charge -0.006745 0.017578 0.007029 -0.021449 0.007036 1.000000 -0.011423 1.000000 -0.012592 0.007596 -0.012601 -0.011043 0.002541 -0.011074 -0.012987
total night minutes -0.008955 0.007681 0.004323 0.022938 0.004324 -0.012584 -0.002093 -0.012592 1.000000 0.011204 0.999999 -0.015207 -0.012353 -0.015180 -0.009288
total night calls -0.013176 0.007123 0.022972 -0.019557 0.022972 0.007586 0.007710 0.007596 0.011204 1.000000 0.011188 -0.013605 0.000305 -0.013630 -0.012802
total night charge -0.008960 0.007663 0.004300 0.022927 0.004301 -0.012593 -0.002056 -0.012601 0.999999 0.011188 1.000000 -0.015214 -0.012329 -0.015186 -0.009277
total intl minutes 0.009514 0.002856 -0.010155 0.021565 -0.010157 -0.011035 0.008703 -0.011043 -0.015207 -0.013605 -0.015214 1.000000 0.032304 0.999993 -0.009640
total intl calls 0.020661 0.013957 0.008033 0.004574 0.008032 0.002541 0.017434 0.002541 -0.012353 0.000305 -0.012329 0.032304 1.000000 0.032372 -0.017561
total intl charge 0.009546 0.002884 -0.010092 0.021666 -0.010094 -0.011067 0.008674 -0.011074 -0.015180 -0.013630 -0.015186 0.999993 0.032372 1.000000 -0.009675
customer service calls -0.003796 -0.013263 -0.013423 -0.018942 -0.013427 -0.012985 0.002423 -0.012987 -0.009288 -0.012802 -0.009277 -0.009640 -0.017561 -0.009675 1.000000
sns.heatmap(corr_matrix);
Image in a Jupyter notebook
sns.pairplot(numeric_data[['total day minutes', 'total day calls', 'total day charge']]);
Image in a Jupyter notebook