В этой статье объясняются различные аспекты науки о данных, которые применяются для прогнозирования того, подпишется ли клиент на премиум-функцию приложения.

У нас есть набор данных, который состоит из сведений о пользователе и показывает, зарегистрировался ли конкретный пользователь на премиум-версию для этого приложения. Мы будем использовать этот набор данных для определения различных идей, скрытых в наборе данных, а также использовать этот набор данных для построения некоторой модели машинного обучения.

Давайте начнем процесс с импорта набора данных.

import pandas as pd
df=pd.read_csv("customer application subscription.csv")
df.head()

После загрузки набора данных мы теперь напишем несколько строк, чтобы узнать о наборе данных в целом.

print("\t\t\tDataset Statistics")
print("Number of variables:-",len(df.columns))
print("Number of observations:-",df.shape[0])
print("Missing Values:-",df.isna().sum().sum())
print("Missing Values %:-",round(df.isna().sum().sum()/df.shape[0]*100,3))
print("Duplicate rows:-",df[df.duplicated(keep="first")].shape[0])
print("Duplicate rows%:-",round(df[df.duplicated(keep="first")].shape[0]/df.shape[0]*100,3))
print("Variable types:-")
a=pd.crosstab(df.dtypes,columns="Count")
for i in pd.crosstab(df.dtypes,columns="Count").index:
    print("\t",str(i).split()[0],a.loc[i][0])

Если мы посмотрим на набор данных, мы увидим, что отсутствующие значения присутствуют только в столбце enrolled_date. Поскольку в 50 000 записях есть только 0,03 % повторяющихся строк, мы не будем их отбрасывать, поскольку в этом нет необходимости.

Теперь мы преобразуем столбец first_open в формат даты и времени, поскольку он имеет тип объекта. Столбец first_open указывает дату и время первого входа в приложение.

df["first_open"]=pd.to_datetime(df["first_open"])
df['first_open_date'] = [d.date() for d in df['first_open']]
df['first_open_time'] = [d.time() for d in df['first_open']]
df=df.drop("first_open",axis=1)

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

a=pd.crosstab(index=df["first_open_date"],columns="count")
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('darkgrid')
import numpy as np
%matplotlib inline
x =  np.arange(datetime(2012,11,23), datetime(2013,7,10), timedelta(days=1)).astype(datetime)
y = a["count"]
y_mean = [a["count"].mean()]*len(x)
fig,ax = plt.subplots(figsize=(17,12))
ax.set_xlabel("Month",fontsize=20)
ax.set_ylabel("Count",fontsize=20)
ax.tick_params(labelsize=15, labelrotation = 20, color ="k")
data_line = ax.plot(x,y, label='Data')
mean_line = ax.plot(x,y_mean, label='Mean', linestyle='--')
legend = ax.legend(loc='upper right')
plt.show()

Как видно из графика, использование приложения сильно колеблется. Это может привести к выводам о том, что причины могут быть связаны непосредственно с приложением, такими как продвижение приложения и т. д., а не с внешними факторами, поскольку они не могут так сильно повлиять.

Теперь мы увидим некоторые сведения из столбца dayofweek. Мы не будем сосредотачиваться на first_open_time, так как оттуда невозможно получить информацию.

import seaborn as sns
sns.set_style('darkgrid')
ct=pd.crosstab(df["dayofweek"],columns="Count")
stacked = ct.stack().reset_index().rename(columns={0:'value'})
g=sns.barplot(x=stacked.dayofweek, y=stacked.value)
plt.title("Count of On which day user logon")

Здесь в dayofweek уникальные значения объясняют следующее:

  • 1: понедельник
  • 2: вторник
  • 3: среда
  • 4: четверг
  • 5: пятница
  • 6: суббота
  • 0: воскресенье

На этом графике показано, что минимальное использование приложения приходится на вторник, а максимальное — на четверг.

Теперь давайте проанализируем столбец час

ct=pd.crosstab(df["hour"],columns="Count")
plt.figure(figsize=(12,12))
plt.tick_params(labelsize=15, labelrotation = 90, color ="k")
stacked = ct.stack().reset_index().rename(columns={0:'value'})
g=sns.barplot(x=stacked.hour, y=stacked.value)

Как мы видим на этом графике, пользователь меньше использует приложение около 9 утра, а максимум — около 15:00.

Давайте посмотрим на столбец age.

df["age"].describe()

plt.hist(df["age"],edgecolor="black",bins=7)
plt.show()

Это показывает, что большинство 75% пользователей моложе 37 лет. Это означает, что производители и компания должны учитывать потребности и отмечать тех людей, чей возраст младше 37 лет, в качестве своей целевой аудитории.

Другие столбцы: screen_list: описывает экраны, которые видят клиенты, numscreens: количество экранов, просмотренных пользователем, мини-игра. : если пользователь играл в мини-игру, которая была включена в приложение, то 1, иначе 0, используемая_премиум_функция: если пользователь воспользовался премиум-функцией приложения, то 1, иначе 0, зарегистрирован: если пользователь приобрел премиум-функции, то 1 иначе 0, enrolled_date: дата и время, когда пользователь приобрел премиум-функции.

Сейчас мы проанализируем приведенные выше столбцы.

groupedvalues=df.groupby('dayofweek')["numscreens","minigame","used_premium_feature","enrolled","liked"].sum().reset_index()
attributes=list(groupedvalues.columns)[1:]
att=attributes[1:]
for i in att:
    print(i)
    sns.countplot(df[i])
    plt.show()

Давайте посмотрим на поведение других столбцов на основе столбца dayofweek:

for i in attributes:
    print(i)
    sns.barplot(x="dayofweek",y=i,data=groupedvalues)
    plt.show()

Давайте посмотрим на поведение других столбцов на основе столбца hour.

for i in attributes:
    print(i)
    plt.figure(figsize=(12,12))
    plt.tick_params(labelsize=15, labelrotation = 90, color ="k")
    sns.barplot(x="hour",y=i,data=groupedvalues2)
    plt.show()

С помощью этих графиков мы, безусловно, можем анализировать неактивность пользователей в дневное время, поскольку большинству пользователей приходится выполнять другие задачи вместо использования этого приложения. Это также может означать, что все рекламные действия, которые могут быть выполнены в приложении, могут быть выполнены во второй половине дня, поскольку большинство пользователей в это время активны.

Давайте проанализируем использование приложения на основе возраста. Поскольку в 50 000 записей есть много уникальных возрастов, мы будем использовать подход визуализации других столбцов на основе «ВОЗРАСТНОЙ ГРУППИ».

groupedvalues3=df.groupby(pd.cut(df['age'], np.arange(15, 106, 10)))["numscreens","minigame","used_premium_feature","enrolled","liked"].sum().reset_index()
for i in attributes:
    print(i)
    plt.figure(figsize=(12,12))
    plt.tick_params(labelrotation = 45)
    sns.barplot(x="age",y=i,data=groupedvalues3)
    plt.show()

На этих графиках мы можем проанализировать, что, хотя 75% нашей аудитории находится в возрасте до 37 лет, наиболее активная возрастная группа находится в диапазоне от 15 до 35 лет.

Поскольку мы выполнили EDA, мы перейдем к выбору функций.

Нахождение корреляции между различными признаками:

for i in df.index:
    x = df.at[i , 'hour']
    y = x[0:3]
    df.at[i , 'hour'] = y
df["hour"]=df["hour"].astype('int64')
import seaborn as sns
df2 = df.drop(['user',  'enrolled_date'], axis = 1)
sns.heatmap(df2.corr(), annot = True)

df3 = df2.drop(['enrolled'], axis = 1)
plt.figure(figsize=(8,8))
sns.barplot(x=df3.corrwith(df2.enrolled).index,y=df3.corrwith(df2.enrolled))
plt.tick_params(labelsize=15, labelrotation = 45)

Приведенный выше график показывает, что час, возраст, мини-игра (отрицательная корреляция), цифровые экраны, мини-игра (положительная корреляция) могут учитываться при построении модели.

После всего этого анализа мы вернемся к нашему фрейму данных, чтобы найти общее время, затраченное пользователем на регистрацию в приложении.

df=pd.read_csv('data.csv')
df["first_open"]=pd.to_datetime(df["first_open"])
df["enrolled_date"]=pd.to_datetime(df["enrolled_date"])
df['time_to_enrolled']=(df.enrolled_date - df.first_open).astype('timedelta64[h]')
import matplotlib.pyplot as plt
plt.figure(figsize=(6,6))
plt.hist(df['time_to_enrolled'].dropna(), range = (0,100))
plt.show()

Как мы видим на этой гистограмме, детали до 50 часов являются хорошими, поскольку другие являются выбросами и могут повлиять на модель, поэтому мы считаем, что клиенты зарегистрировались как 0.

df.loc[df.time_to_enrolled > 50, 'enrolled'] = 0

Столбец screen_list может оказаться очень полезным, поскольку его можно использовать для целей моделирования. Но этот столбец является строкой. Поэтому, чтобы использовать это, нам нужно закодировать этот столбец, что займет много времени, поскольку он должен обрабатывать около 50000 строк.

Прежде чем продолжить, нам нужен еще один пакет, который называется «mlxtend». Чтобы установить его, используйте эту строку в cmd/Anaconda Prompt:

pip install mlxtend

После этого напишите следующие строки:

for i in range(len(df["screen_list"])):
    df["screen_list"][i]=df["screen_list"][i].split(',')
from mlxtend.preprocessing import TransactionEncoder 
transactionEncoder = TransactionEncoder()
txnn=transactionEncoder.fit(df["screen_list"]).transform(df["screen_list"])
dfnn=pd.DataFrame(txnn,columns=transactionEncoder.columns_)
df=df.join(dfnn, how="outer")
from sklearn.preprocessing import LabelEncoder
le=LabelEncoder()
l=list(transactionEncoder.columns_)
for i in l:
    try:
        df[i]=le.fit_transform(df[i])
    except:
        pass

Исходя из этого, мы собираемся преобразовать наш набор данных и выбрать только те функции, которые требуются модели, как обсуждалось выше.

a1=df[["hour","age","numscreens","used_premium_feature","minigame"]]
for i in df.index:
    x = a1.at[i , 'hour']
    y = x[0:3]
    a1.at[i , 'hour'] = y
a1["hour"]=a1["hour"].astype('int64')
a2=df[transactionEncoder.columns_]
a1=a1.join(a2, how="outer")
X=a1
Y=df["enrolled"]
from sklearn.model_selection import train_test_split
xtrain,xtest,ytrain,ytest=train_test_split(X,Y,test_size=0.3,random_state=42)

Теперь наши данные проходят через модели. Давайте попробуем пропустить нашу модель через различные модели ML.

  1. Логистическая регрессия:
from sklearn.linear_model import LogisticRegression
le=LogisticRegression(random_state = 42, penalty = 'l1')
le.fit(xtrain,ytrain)
le.score(xtest,ytest)

После запуска кода мы получаем следующую оценку:

0.868

Мы получили впечатляющий результат по этому набору данных. Проверим на тренировочном наборе, есть ли случай переобучения или нет.

le.score(xtrain,ytrain)

После запуска кода мы получаем следующую оценку: -

0.8619428571428571

Кажется, что нет случая переобучения

2. Классификатор дерева решений
Мы будем использовать GridSearchCV для настройки гиперпараметров\

from sklearn.tree import DecisionTreeClassifier
from sklearn import metrics
from sklearn.model_selection import GridSearchCV
tuned_parameters = [{'criterion': ['gini','entropy'],
'max_depth': range(2,10)}]
clf_tree = DecisionTreeClassifier()
clf = GridSearchCV(clf_tree,
tuned_parameters,
cv=10,
scoring='roc_auc')
clf.fit(xtrain, ytrain )

Чтобы найти параметры: -

clf.best_params_

Вот что мы получили.

{'criterion': 'entropy', 'max_depth': 7}

Таким образом, мы будем использовать его, чтобы найти счет.

clf_tree2 = DecisionTreeClassifier(criterion = 'entropy',
max_depth = 7 )
clf_tree2.fit( xtrain, ytrain )
tree_predict2 = clf_tree2.predict( xtest )
metrics.roc_auc_score( ytest, tree_predict2 )

Получен следующий балл:

0.8662688484194627

Мы также можем использовать другие модели ML для того же. Это моя первая статья, поэтому ценные отзывы высоко ценятся. Спасибо и удачного кодирования!

Ссылка на блокнот: - https://github.com/luv8860/Projects/blob/master/Customer%20application%20subscription.ipynb

Ссылка на набор данных: -

https://github.com/luv8860/Projects/blob/master/customer%20application%20subscription.csv