У всех нас есть датасет по контакту. В нём лежит информация про всех нас. Эту информацию надо как следует проанализировать. Именно этим мы сейчас продолжим заниматься. В этот раз с картинками!
Для начала подгрузите все необходимые библиотеки: pandas
, matplotlib.pyplot
, seaborn
и включите опцию, отвечающую за прорисовку картинок прямо в питонячей тетрадке.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
Подгрузите данные профилей и данные по фотографиям
# В этой табличке лежат данные по профилю человека
df_profile = pd.read_csv('../data/vk_download/vk_data_profile.csv',sep='\t')
# В этой табличке лежат данные по фотографиям человека
df_photo = pd.read_csv('../data/vk_download/vk_data_photo.csv',sep='\t')
Склеим табличку по полю uid
df = pd.merge(df_profile, df_photo, how='right', on='uid')
df.head()
Unnamed: 0_x | uid | Unnamed: 0.1 | first_name | last_name | is_closed | city | home_town | male_dummy | relation_cat | ... | photo_repost_cnt | photo_repost_max | photo_repost_mean | photo_repost_median | photo_text | photo_text_len_cnt | photo_yer_mean | vk_photo_ava_change_cnt | vk_photo_text_url_len_cnt | vk_photo_wall_ph_post_cnt | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 182152789 | 0 | Александра | Абашкова | False | Москва | Москва | 0 | не указано | ... | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 1.333333 | 0.0 | 0.0 | 0.0 | |
1 | 1 | 148020433 | 1 | Анастасия | Чуфистова | False | Рязань | Рязань | 0 | не указано | ... | 2.0 | 1.0 | 0.105263 | 0.0 | 0.0 | 3.166667 | 0.0 | 0.0 | 0.0 | |
2 | 2 | 138413935 | 2 | Александр | Головачев | False | Москва | Омск | 1 | не женат/не замужем | ... | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 2.333333 | 0.0 | 0.0 | 0.0 | |
3 | 3 | 366261055 | 3 | Анна | Лобанова | False | NaN | NaN | 0 | не указано | ... | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 12.500000 | 0.0 | 0.0 | 0.0 | |
4 | 4 | 111252392 | 4 | Алексей | Пузырный | False | NaN | NaN | 1 | NaN | ... | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 8.750000 | 0.0 | 0.0 | 0.0 |
5 rows × 85 columns
Давайте посмотрим на все названия колонок, которые есть в таблице.
df.columns
Index(['Unnamed: 0_x', 'uid', 'Unnamed: 0.1', 'first_name', 'last_name', 'is_closed', 'city', 'home_town', 'male_dummy', 'relation_cat', 'relation_partner', 'byear', 'bmonth', 'bday', 'country', 'facebook_dummy', 'instagram_dummy', 'skype_dummy', 'twitter_dummy', 'home_phone_dummy', 'mobile_phone_dummy', 'site_dummy', 'folowers_cnt', 'university_str', 'faculty_str', 'about_str', 'activities_str', 'books_str', 'interests_str', 'movies_str', 'music_str', 'quotes_str', 'tv_str', 'games_str', 'can_post_dummy', 'can_see_all_posts_dummy', 'can_see_audio_dummy', 'can_write_private_message_dummy', 'has_mobile_dummy', 'has_ava_dummy', 'wall_comments_dummy', 'albums_cnt', 'audio_cnt', 'followers_cnt', 'friends_cnt', 'gifts_cnt', 'groups_cnt', 'mutual_friends_cnt', 'photos_cnt', 'subscriptions_cnt', 'user_photos_cnt', 'videos_cnt', 'pages_cnt', 'alco_love_cat', 'smoke_love_cat', 'religion_str', 'inspired_by_str', 'life_main_cat', 'people_main_cat', 'political_cat', 'lang_cnt', 'english_dummy', 'change_city_school_cnt', 'last_bukva_class_str', 'schools_cnt', 'is_bmm', 'in_hse_memes_group', 'likes_memes', 'Unnamed: 0_y', 'photo_cnt', 'photo_like_cnt', 'photo_like_max', 'photo_like_mean', 'photo_like_median', 'photo_month_mean', 'photo_repost_cnt', 'photo_repost_max', 'photo_repost_mean', 'photo_repost_median', 'photo_text', 'photo_text_len_cnt', 'photo_yer_mean', 'vk_photo_ava_change_cnt', 'vk_photo_text_url_len_cnt', 'vk_photo_wall_ph_post_cnt'], dtype='object')
Мы видим, что часть из них кончается на cnt
. Это колонки-счётчики. В них лежат такие переменные как количество фоток, лайков, репостов и тд
variables_cnt = [item for item in df.columns if item[-3:] == 'cnt']
variables_cnt
['folowers_cnt', 'albums_cnt', 'audio_cnt', 'followers_cnt', 'friends_cnt', 'gifts_cnt', 'groups_cnt', 'mutual_friends_cnt', 'photos_cnt', 'subscriptions_cnt', 'user_photos_cnt', 'videos_cnt', 'pages_cnt', 'lang_cnt', 'change_city_school_cnt', 'schools_cnt', 'photo_cnt', 'photo_like_cnt', 'photo_repost_cnt', 'photo_text_len_cnt', 'vk_photo_ava_change_cnt', 'vk_photo_text_url_len_cnt', 'vk_photo_wall_ph_post_cnt']
Разбиритесь как работает и устроен этот цикл, если вы ещё не разбираетесь. Почитать об этом можно вот тут. Чуть ниже вам предстоит написать свой такой.
Вытащите из переменных счётчиков только те, которые отвечают за фото. Постройте для них гистограммы (для удобства используйте логарифмическое скалирование). Как думаете, в каких переменных есть выбросы? Какие из переменных неинформативны? Почему?
Ответ: Выбросы есть везде, где длинные хвосты. То есть это почти каждая переменная. Неинформативная photo_ava_change_cnt
. Она принимает только одно значение. Какой вообще в ней смысл?!
photo_vars = [var_name for var_name in variables_cnt if 'photo' in var_name]
df[photo_vars].hist(figsize = (15,8), log=True);
Кто больше постит фотографий, девушки или парни? чьи фото собирают больше лайков? (общее количество лайков, медиана и среднее)
features = ['photo_cnt', 'photo_like_cnt', 'photo_like_median', 'photo_like_mean']
fig, axes = plt.subplots(4, 1, figsize=(12,24))
for i in range(4):
axes[i].hist([df[features[i]] [df.male_dummy == 1],df[features[i]] [df.male_dummy == 0]], log=True, bins=20)
axes[i].legend(['male', 'female'], )
axes[i].set_title(features[i])
fig.show()
/usr/local/lib/python3.7/site-packages/numpy/lib/histograms.py:839: RuntimeWarning: invalid value encountered in greater_equal keep = (tmp_a >= first_edge) /usr/local/lib/python3.7/site-packages/numpy/lib/histograms.py:840: RuntimeWarning: invalid value encountered in less_equal keep &= (tmp_a <= last_edge) /usr/local/lib/python3.7/site-packages/matplotlib/figure.py:445: UserWarning: Matplotlib is currently using module://ipykernel.pylab.backend_inline, which is a non-GUI backend, so cannot show the figure. % get_backend())
Давайте добавим к нашим переменным (описывающим фотографии) количество друзей, количество подарков и пол
vars_interesting = features
vars_interesting.extend(['male_dummy', 'friends_cnt', 'gifts_cnt'])
df[vars_interesting].head()
photo_cnt | photo_like_cnt | photo_like_median | photo_like_mean | male_dummy | friends_cnt | gifts_cnt | |
---|---|---|---|---|---|---|---|
0 | 4.0 | 309.0 | 72.0 | 77.250000 | 0 | 298.0 | NaN |
1 | 19.0 | 2894.0 | 152.0 | 152.315789 | 0 | 408.0 | 203.0 |
2 | 7.0 | 2406.0 | 328.0 | 343.714286 | 1 | 2969.0 | NaN |
3 | 50.0 | 1310.0 | 25.0 | 26.200000 | 0 | 214.0 | 24.0 |
4 | 35.0 | 1375.0 | 19.0 | 39.285714 | 1 | 336.0 | 227.0 |
[1] Визуализируйте вытащенные признаки попарно. Постройте pairplot
для всех пар. На диагонали расположите оценки плотностей для признаков. Для этого используйте опцию diag_kind = 'kde'
. С помощью параметра hue
разбейте все наблюдения на мужские и женские, чтобы они отражались на картинках разными цветами.
sns.pairplot(df[vars_interesting], diag_kind="kde", hue='male_dummy', dropna=True);
Давайте для удобства визуализации прологарифмуем наш датасет (предварительно заполнив пропуски нулями или выкинув их)
import math
df_na_zero = df[vars_interesting].fillna(0)
for column in df_na_zero.columns:
if column == 'male_dummy':
continue
df_na_zero[column] = df_na_zero[column].map(lambda x: math.log(1 + x))
sns.pairplot(df_na_zero, diag_kind="kde", hue='male_dummy', dropna=True);
df_na_drop = df[vars_interesting].dropna()
for column in df_na_zero.columns:
if column == 'male_dummy':
continue
df_na_drop[column] = df_na_drop[column].map(lambda x: math.log(1 + x))
sns.pairplot(df_na_drop, diag_kind="kde", hue='male_dummy', dropna=True);
[2] Дайте ответы на соедущие вопросы. Свои мысли пишите прямо здесь!
Ответ: очевидно, медиана и среднее почти 1:1
Ответ: на логарифмированных графиках почти линейные зависимости между количеством фото и лайков на них, количеством друзей и подарков, значит исходные близки к y=xa
Ответ: Да есть. Подойдут любые попытки рассказать о том, что в некоторых облаках точки далеко от основного сгустка.
[1] Отлично! Половина домашки осталась позади. Давайте теперь для тех же самых признаков построим матрицу корреляций и провизуализируем её с помощью heatmap
.
plt.subplots(figsize=(8, 8))
sns.heatmap(df[vars_interesting].corr( ), square=True,
annot=True, fmt=".1f", linewidths=0.1, cmap="RdBu");
plt.subplots(figsize=(8, 8))
sns.heatmap(df_na_zero.corr( ), square=True,
annot=True, fmt=".1f", linewidths=0.1, cmap="RdBu");
plt.subplots(figsize=(8, 8))
sns.heatmap(df_na_drop.corr( ), square=True,
annot=True, fmt=".1f", linewidths=0.1, cmap="RdBu");
[2] Между какими переменными корреляция самая высокая? Почему? Она отрицательная или положительная. Прокомментируйте все клетки, где она оказалась ≥0.3 либо ≤−0.2.
Ответ:
[1] Дамми-переменная это переменная, которая принмает два значения. Либо 1, если человек обладает закодированным в ней свойством, либо 0, если не обладает. В нашей таблице все дамми-переменные оканчиваются на суффикc dummy
.
Возьмите переменную instagram_dummy
. Она принимает значение 1, если у пользователя на страничке есть ссылка на инстаграм. Возьмите переменную male_dummy
. Она примает значение 1, если пользователь парень. Постройте картинку, на которой будет видно как между собой соотносятся владельцы инстаграмма по полу.
dff = df.pivot_table(index='instagram_dummy', columns='male_dummy', values='first_name', aggfunc='count')
dff
male_dummy | 0 | 1 |
---|---|---|
instagram_dummy | ||
0 | 174 | 168 |
1 | 56 | 27 |
dff.plot(kind='bar', stacked=True)
<matplotlib.axes._subplots.AxesSubplot at 0x13207b470>
Правда ли, что девушки чаще указыают наличие инстаграмма на своей страничке?
Ответ: Да. Во втором столбике синяя фигня толще.
[1] Категориальная переменная обычно принимает значения из какого-то фиксированного множества. Например, переменная political_cat
описывает к какой категории относятся политические взгляды юзера. Постройте для этой переменной столбиковую диаграмму. Разбиритесь по документации как сделать у столбиков горизонтальное расположение. Можно ли сделать исходя из картинки вывод, что в вышке одни либералы? Почему?
sns.catplot(y = 'political_cat', data=df, kind='count');
как политические взгляды распределены по полам?
Ответ: Можно визуализировать, но выводы делать нельзя, мало данных
dff = df.pivot_table(index='political_cat', columns='male_dummy', values='first_name', aggfunc='count')
dff
male_dummy | 0 | 1 |
---|---|---|
political_cat | ||
индифферентные | 1.0 | 1.0 |
коммунистические | 1.0 | NaN |
либеральные | 1.0 | 1.0 |
либертарианские | NaN | 1.0 |
социалистические | NaN | 1.0 |
умеренные | 2.0 | 3.0 |
dff.plot(kind='bar', stacked=True)
<matplotlib.axes._subplots.AxesSubplot at 0x136c336d8>
[n] Удиви нас. Попробуй найти в данных какую-то классную особенность и визуализируйте её. Если у тебя это получится, мы поставим дополнительные баллы. Если вы найдёте полную фигню (сколько всего друзей у Маши или типа того), баллов не будет. Найденный факт реально должен выносить мозг и сносить крышу.
# ваш код
Настрадался? Выскажи всё, что думаешь обо всём этом в анонимке по четвёртой домашке.