Как вы все, наверное, уже знаете, недавно были опубликованы дампы базы данных AshleyMadison. Я решил не упускать возможность и проанализировать реальные данные платформы знакомств.
Попробуем спрогнозировать платежеспособность клиента, исходя из его характеристик, таких как возраст, рост, вес, привычки и т.д.
Попробуем?
В этом примере я буду использовать блокнот iPython. Для тех, кто занимается анализом данных на Python и еще не использовал iPython-ноутбук - настоятельно рекомендую!
Для построения модели мы будем использовать обезличенные данные.
1. Подготовка данных в MySQL Для начала загрузим дампы в MySQL и удалим всех пользователей с id < 35,000,000 for ease of further processing. I took the member_details and aminno_member tables. Загрузка данных происходит не очень быстро даже на сервере с SSD (некоторые таблицы весят около 10 ГБ) Далее нам нужно заполнить данные платежа из csv и получить сумму для каждого пользователя.
Результатом является таблица выплат с полями id и sum. 2. Загрузите данные в панды Объединяем 3 таблицы по идентификатору пользователя и получаем DataFrame для дальнейшей обработки.
Мы берем пользователей только с фотографиями, думаю, что это признак хоть какой-то активности в системе:
Извлекаем год и месяц рождения:engine = create_engine(' mysql://login:pass@localhost:3306/db ') # Creating MySQL engine sql = """ SELECT md.pnum, p.sum, am.gender, am.photos_public, md.profile_weight, md.profile_height, md.eye_color, md.hair_color, md.dob, md.profile_smoke, md.profile_ethnicity, md.profile_bodytype, md.profile_initially_seeking FROM `member_details` AS md JOIN `aminno_member` AS am ON md.pnum = am.pnum LEFT JOIN pays AS p ON md.pnum = p.id WHERE md.dob is not null AND (am.photos_public > 0 OR p.sum is not NULL) """ df = pd.read_sql_query(sql, engine).
fillna(0).
set_index('pnum') #Reading data from mysql DB to pandas dataframe
df['month_of_birth'] = df['dob'].
apply(lambda x:x.month)
df['year_of_birth'] = df['dob'].
apply(lambda x:x.year)
Попробуем проанализировать, зависит ли целевая переменная (оплатил/не заплатил) от характеристик пользователя? Есть ли смысл строить модель? Разделим проанализированных пользователей на 2 части: df0 — те, кто хоть немного заплатил, df1 — ничего не заплатил.
THRESHOLD = 0.0001
df0 = df[(df['sum'] > THRESHOLD)]
df1 = df[(df['sum'] < THRESHOLD)]
Строим по 2 гистограммы для каждого из пользовательских параметров.
Красный – те, кто заплатил, синий – те, кто не заплатил.
cols = ['profile_weight','profile_height','year_of_birth','month_of_birth',
'eye_color', 'hair_color','profile_smoke', 'profile_ethnicity',
'profile_bodytype', 'profile_initially_seeking','gender']
for col in cols:
plt.figure(figsize=(10,10))
df0[col].
hist(bins=50, alpha=0.9, color = 'red', normed=1) df1[col].
hist(bins=50, alpha=0.7, normed=1)
plt.title(col)
plt.show()
Давайте рассмотрим самые интересные из них:
Год рождения:
Результат вполне ожидаемый: возраст влияет на целевую переменную.
Пожилые люди платят охотнее.
Пик гистограммы у плательщиков приходится примерно на 35-летний возраст.
Масса:
Здесь интереснее: те, кто больше весит, охотнее платят. Хотя это тоже вполне логично
Высота:
Высокие люди платят немного охотнее.
Распределение очень неравномерное.
Возможно, рост на сайте определяется не количеством, а интервалом.
Курение:
По поводу названия статьи.
Есть четкая зависимость, вопрос - что означают значения 1,2,3,4? Остальные пользовательские параметры не дают такой интересной картины, хотя тоже имеют свою лепту.
Здесь Существует полная версия этого блокнота, где можно увидеть все гистограммы.
2. Прогнозирование вероятности выплаты
Сначала выберем целевую переменную (оплачено/не оплачено), которую мы будем прогнозировать: y = (df['sum'] > THRESHOLD).
astype(np.int32)
Выделим категориальные признаки и проведем их бинаризацию: categorical = ['month_of_birth',
'eye_color', 'hair_color','profile_smoke', 'profile_ethnicity',
'profile_bodytype', 'profile_initially_seeking']
ohe = preprocessing.OneHotEncoder(dtype=np.float32)
Xcategories = ohe.fit_transform(df[categorical]).
todense()
Выделим метрические признаки и объединим их с результатом бинаризации: numeric = ['gender','profile_weight','profile_height','year_of_birth']
Xnumeric = df[numeric].
as_matrix()
X = np.hstack((Xcategories,Xnumeric))
Делим выборку на 2 части 90% и 10%.
На первом этапе мы обучим и настроим модель.
Во-вторых, оценить точность полученной модели.
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.1, random_state=7)
Обучаем классификатор RandomForest и подбираем оптимальные параметры.
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn import decomposition, pipeline, metrics, grid_search
rf = RandomForestClassifier(random_state=7, n_jobs=4)
scl = StandardScaler()
clf = pipeline.Pipeline([('scl', scl),
('rf', rf)])
param_grid = {'rf__n_estimators': (100,200),
'rf__max_depth': (10,20),
}
model = grid_search.GridSearchCV(estimator = clf, param_grid=param_grid, scoring='roc_auc',
verbose=10, cv=3)
model.fit(X_train, y_train)
print("Best score: %0.3f" % model.best_score_)
print("Best parameters set:")
best_parameters = model.best_estimator_.get_params()
for param_name in sorted(param_grid.keys()):
print("\t%s: %r" % (param_name, best_parameters[param_name]))
Best score: 0.802
Best parameters set:
Теги: #анализ данных #машинное обучение #Интеллектуальный анализ данных #программирование #Интеллектуальный анализ данных #Большие данные #математика #Машинное обучение
-
Базовые Шаблоны Ui/Ux
19 Oct, 24