Анализ социальных сетей и большие данные. Второй семестр. Практическое занятие по анализу виртуальных сообществ

Author

Омельченко Д.А.

Краткое содержание предыдущих серий

На прошлых занятиях мы учились делать выгрузку по сообществам через API VK

install.packages("vkR")# эта строчка нужна только тем, кто еще не установил пакет vkR
library(vkR)
#получить ключ
vkOAuth(11111111)# в скобках - id приложения в ВК, которое создавали на предыдущих занятиях, откроется браузер, скопировать ключ до знака &
#установить ключ
setAccessToken(access_token="vk1.a....ТУТ ВАШ КЛЮЧ до - скопировать ДО знака & перед &expires_in=86400&user_id")
# установить версию API
v<-setAPIVersion("5.89")
#Выгрузить информацию об ID пользователей группы (пример по группе кафедры)
group_kaf<-getGroupsMembersExecute(group_id = 211524072) # это пример по кафедре у Вас свои группы
kaf<-getGroupsMembersExecute(group_id = 211524072)
ign<-getGroupsMembersExecute(group_id = "ign21")
rnd<-getGroupsMembersExecute("rndaltai")
#выгрузить информацию о пользователях (примеры по кафедре, ИГН и Дому народов Алтайского края)
kaf_info<-getUsersExecute(group_kaf, fields='sex, bdate, city, occupation')
ign_info<-getUsersExecute(group_ign, fields='sex, bdate, city, occupation')
rnd_info<-getUsersExecute(group_rnd, fields='sex, bdate, city, occupation')

Нам нужно сделать обобщающую таблицу с основными сведениями. Допустим, у нас есть таблицы по трем группам - кафедры, ИГН и Дома народов Алтайского края. Они называются kaf_info, ign_info, rnd_info

Чтобы не делать одну и ту же работу несколько раз, соединим все таблицы в одну большую таблицу, которую назовем info`. Но, прежде чем это сделать, чтобы наши данные по разным группам не перемешались, создадим в каждой таблице переменную принадлежности к группе:

kaf_info$group<-"Кафедра"
ign_info$group<-"ИГН"
rnd_info$group<-"РНД"

Теперь соединим все таблицы в одну:

info<-rbind(kaf_info,ign_info, rnd_info )

Например, давайте посмотрим, сколько участников в каждой группе:

table(info$group)

    ИГН Кафедра     РНД 
   3377     206     677 

То же самое, но в процентах:

#В процентах
prop.table(table(info$group))*100

      ИГН   Кафедра       РНД 
79.272300  4.835681 15.892019 

Однако, анализировать информацию по каждой переменной не очень удобно. Нам хотелось бы провести анализ сразу и сделать одну таблицу по всем переменным. К сожалению, так сделать не получится, хотя бы потому, что некоторые переменные, например, интересы - это поле со свободными ответами и делать по ним таблицу не очень целесообразно, нужно описывать в целом, проводя качественный анализ “вручную”.

Что касается остальных переменных, то прежде, чем сделать по ним таблицу, мы должны осуществить обработку данных:

  • вычислить возраст по дате рождения
  • перекодировать переменные (заменить коды на метки)
  • некоторые переменные являются вложенными (city, occupation, personal) то есть это не одна, а несколько переменных в одной группе (идентификатор и название города, тип занятий, название организации и др.) - соответственно, нам нужно эти переменные привести к общему табличному виду.

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

install.packages(c("readr", "lubridate", "dplyr", "tidyr", "gtsummary"))

Эти пакеты имеют следующее предназначение:

  • readr - работа с прямоугольными таблицами (импорт из разных источников) и парсинг различных форматов
  • lubridate - работа с временными данными
  • dplyr - всевозможные трансформации данных, такие как отбор переменных, фильтрация наблюдений, перекодировка, группировка, вычисление новых переменных и пр.
  • tidyr - помощь в трансформации данных в “чистый формат”, когда в каждой строке содержится одно наблюдение и в каждом столбце - только одна переменная
  • gtsummary - создание красивых таблиц для научных исследований.

Вычисление возраста

Начнем с вычисления возраста. Разобьем наш код на несколько этапов. Прежде всего, подключим нужные библиотеки:

library(lubridate)
library(readr)

Перекодируем переменную bdate в формат даты (неизбежно, часть данных, где дата рождения была введена не полностью, потеряется), а затем вычислим дату рождения путем вычитания из сегодняшней даты даты рождения пользователя группы:

# 1. Конвертируем переменную bdate в дату
info$bdate2<-readr::parse_datetime(info$bdate, "%d%.%m%.%Y")
Warning: 1786 parsing failures.
row col             expected actual
  2  -- date like %d%.%m%.%Y  15.12
  5  -- date like %d%.%m%.%Y  19.5 
 10  -- date like %d%.%m%.%Y  10.7 
 11  -- date like %d%.%m%.%Y  22.4 
 12  -- date like %d%.%m%.%Y  2.12 
... ... .................... ......
See problems(...) for more details.
# 2.Создадим переменную возраста с помощью функций time_length() и difftime().
info$age<-time_length(difftime(today(), info$bdate2), "years")

То, что появилось предупреждение, ничего страшного, это означает, что программа не смогла правильно распознать все даты.

Посмотрим, что у нас получилось:

summary(info$age)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
  14.01   19.66   21.68   26.85   27.75  122.86    2391 

Как видим, у нас довольно большой размах по возрасту - от 17 (почти 18) до 66 лет, средний возраст (mean) - составил 26,8 года, медианный (median)- 21,7 года. Велико и количество пропущенных значений - 2391 случай из 4260. Кроме того, мы видим, что максимальный возраст очень велик, вряд ли кто-то дожил до 100 лет))).

Давайте заменим на пропущенные все значения возраста, превышающие 80ялет:

info$age[info$age >100] <- NA

Проверим. что у нас получилось:

summary(info$age)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
  14.01   19.64   21.63   26.22   27.41   99.16    2404 

Видим, что теперь есть те, кому 99))) Давайте посмотрим на гистограмму:

hist(info$age, col = "steelblue")

Видим, что есть разные единичные ответы больше 70 лет, поэтому при описании лучше ориентироваться на медианный возраст.

Анализ пропущенных значений

Мы видим, что в нашей таблице много пропусков. Давайте посмотрим, сколько у нас пропущенных значений по каждому столбцу в общей таблице:

#Посмотрим количество пропущенных значений по каждому столбцу
colMeans(is.na(info))*100
               id             bdate                id             title 
          0.00000          14.20188          40.11737          40.11737 
               id              name              type        country_id 
         35.63380          33.14554          33.14554          87.48826 
          city_id     graduate_year               sex        first_name 
         53.75587          55.25822           0.00000           0.00000 
        last_name can_access_closed         is_closed       deactivated 
          0.00000           0.00000           0.00000          97.84038 
            group            bdate2               age 
          0.00000          56.12676          56.43192 

Видим, что даже по основным переменным данных сильно не хватает: даже такие переменные, как город проживания, пропущены у 40% пользователей.

Отбор переменных для анализа и перекодировка

Давайте отберем в отдельный набор переменные, которые мы будем представлять в виде отдельной таблицы.

Поскольку при выгрузке создается объект в формате VK object, нам нужно перевести его в классический табличный вид:

library(tibble)
info<-as_tibble(info)

Теперь уберем вложенность некоторых переменных:

library(tidyr)
info<-info %>%
  unnest(cols = c(city, occupation),names_sep = "_" )

Сделаем окончательный отбор переменных в таблицу:

library(dplyr)
#отберем в набор наиболее интересные показатели
info<-info %>%
  select(group, age, sex, city_title, occupation_type)

Сделаем перекодировку переменных

Наиболее быстрый способ трансформировать данные (вычислить новые переменные, перекодировать и пр.) - воспользоваться возможностями пакета dplyr из библиотеки tidyverse.

Как понять, как перекодировать, и что означает код? Посмотреть документацию - (справочник по API ВК)[https://dev.vk.com/ru/reference/objects/user].

Сделаем перекодировку по полу и по занятости:

info<-info %>%
  mutate(sex=case_when(
   sex==1~"Женский",
   sex==2~"Мужской"
  ),
  occupation_type=case_when(
   occupation_type=="work"~"Работа",
   occupation_type=="university"~"Высшее образование",
   occupation_type=="school"~"Среднее образование",
    ))

Создаем таблицу по группе

Чтобы сделать большую красивую таблицу, воспользуемся пакетом: gtsummary:

library(gtsummary)
table<-info %>%
  tbl_summary(missing="ifany", by=group)
table
Characteristic ИГН, N = 3,3771 Кафедра, N = 2061 РНД, N = 6771
age 21 (19, 24) 24 (20, 31) 37 (27, 47)
    Unknown 1,879 122 403
sex


    Женский 2,584 (77%) 174 (84%) 518 (77%)
    Мужской 792 (23%) 32 (16%) 159 (23%)
    Unknown 1 0 0
city_title


    Abu Dhabi 1 (<0.1%) 0 (0%) 0 (0%)
    Albuquerque 1 (<0.1%) 0 (0%) 0 (0%)
    Atlanta 1 (<0.1%) 0 (0%) 0 (0%)
    Barkow 1 (<0.1%) 0 (0%) 0 (0%)
    Batman 0 (0%) 1 (0.8%) 0 (0%)
    Bebra 2 (0.1%) 0 (0%) 0 (0%)
    Beijing 1 (<0.1%) 0 (0%) 0 (0%)
    Berlin 0 (0%) 0 (0%) 6 (1.1%)
    Bielefeld 0 (0%) 0 (0%) 1 (0.2%)
    Boston 1 (<0.1%) 0 (0%) 0 (0%)
    Busan 1 (<0.1%) 0 (0%) 0 (0%)
    California 1 (<0.1%) 0 (0%) 0 (0%)
    Capri 1 (<0.1%) 0 (0%) 0 (0%)
    Chiba 1 (<0.1%) 0 (0%) 0 (0%)
    Dortmund 0 (0%) 0 (0%) 1 (0.2%)
    Dresden 0 (0%) 0 (0%) 1 (0.2%)
    Florida City 1 (<0.1%) 0 (0%) 0 (0%)
    Frankfurt am Main 0 (0%) 0 (0%) 1 (0.2%)
    Hamburg 0 (0%) 0 (0%) 1 (0.2%)
    Hannover 0 (0%) 0 (0%) 1 (0.2%)
    Hattingen 0 (0%) 0 (0%) 1 (0.2%)
    Honolulu 1 (<0.1%) 0 (0%) 0 (0%)
    Kanavayén 1 (<0.1%) 0 (0%) 0 (0%)
    Kawasaki 1 (<0.1%) 0 (0%) 0 (0%)
    Kyōto 1 (<0.1%) 0 (0%) 0 (0%)
    Lanzhou 1 (<0.1%) 0 (0%) 0 (0%)
    Lenzburg 0 (0%) 0 (0%) 1 (0.2%)
    Lichtenfels 0 (0%) 0 (0%) 1 (0.2%)
    Linz 1 (<0.1%) 0 (0%) 0 (0%)
    Liverpool 1 (<0.1%) 0 (0%) 0 (0%)
    London 1 (<0.1%) 0 (0%) 0 (0%)
    Lörrach 0 (0%) 0 (0%) 1 (0.2%)
    Los Angeles 2 (0.1%) 0 (0%) 0 (0%)
    Lübeck 0 (0%) 0 (0%) 1 (0.2%)
    Madrid 1 (<0.1%) 0 (0%) 0 (0%)
    Malibu 1 (<0.1%) 0 (0%) 0 (0%)
    Moscow 1 (<0.1%) 0 (0%) 0 (0%)
    München 1 (<0.1%) 0 (0%) 0 (0%)
    New York City 1 (<0.1%) 0 (0%) 0 (0%)
    Nitzana 1 (<0.1%) 0 (0%) 0 (0%)
    Ōsaka 1 (<0.1%) 0 (0%) 0 (0%)
    Palermo 1 (<0.1%) 0 (0%) 0 (0%)
    Paris 1 (<0.1%) 0 (0%) 0 (0%)
    Philadelphia 1 (<0.1%) 0 (0%) 0 (0%)
    Portorož 1 (<0.1%) 0 (0%) 0 (0%)
    Québec 1 (<0.1%) 0 (0%) 0 (0%)
    Salzburg 0 (0%) 0 (0%) 1 (0.2%)
    Sanya 1 (<0.1%) 0 (0%) 0 (0%)
    Seoul 1 (<0.1%) 0 (0%) 0 (0%)
    Siegburg 0 (0%) 0 (0%) 1 (0.2%)
    Stockholm 1 (<0.1%) 0 (0%) 0 (0%)
    Taiyuan 1 (<0.1%) 0 (0%) 0 (0%)
    Tokyo 3 (0.2%) 0 (0%) 0 (0%)
    Weiden in der Oberpfalz 0 (0%) 0 (0%) 1 (0.2%)
    Witten 0 (0%) 0 (0%) 1 (0.2%)
    Wrocław 1 (<0.1%) 0 (0%) 0 (0%)
    Xingtai 1 (<0.1%) 0 (0%) 0 (0%)
    Yamatotakada 1 (<0.1%) 0 (0%) 0 (0%)
    Yokohama 1 (<0.1%) 0 (0%) 0 (0%)
    Zug 0 (0%) 0 (0%) 1 (0.2%)
    Абакан 3 (0.2%) 1 (0.8%) 0 (0%)
    Алейск 4 (0.2%) 0 (0%) 1 (0.2%)
    Алейский 1 (<0.1%) 0 (0%) 0 (0%)
    Александровское 1 (<0.1%) 0 (0%) 0 (0%)
    Алматы 6 (0.3%) 0 (0%) 0 (0%)
    Алтайское 2 (0.1%) 0 (0%) 0 (0%)
    Анжеро-Судженск 2 (0.1%) 1 (0.8%) 0 (0%)
    Астана 2 (0.1%) 0 (0%) 0 (0%)
    Ачинск 1 (<0.1%) 0 (0%) 0 (0%)
    Баево 1 (<0.1%) 0 (0%) 0 (0%)
    Балашиха 1 (<0.1%) 0 (0%) 0 (0%)
    Барнаул 1,359 (72%) 89 (67%) 314 (60%)
    Барнаул (деревня) 3 (0.2%) 0 (0%) 4 (0.8%)
    Белгород 0 (0%) 1 (0.8%) 0 (0%)
    Белокуриха 4 (0.2%) 0 (0%) 1 (0.2%)
    Белояровка 1 (<0.1%) 0 (0%) 0 (0%)
    Бердск 1 (<0.1%) 0 (0%) 0 (0%)
    Бийск 31 (1.6%) 5 (3.8%) 6 (1.1%)
    Бишкек 3 (0.2%) 2 (1.5%) 1 (0.2%)
    Борзя 1 (<0.1%) 0 (0%) 0 (0%)
    Борисов 1 (<0.1%) 0 (0%) 0 (0%)
    Братск 2 (0.1%) 0 (0%) 0 (0%)
    Брянск 0 (0%) 0 (0%) 1 (0.2%)
    Бурла 2 (0.1%) 0 (0%) 1 (0.2%)
    Валдай 0 (0%) 0 (0%) 1 (0.2%)
    Верх-Уймон 0 (0%) 0 (0%) 2 (0.4%)
    Витим 1 (<0.1%) 0 (0%) 0 (0%)
    Вичуга 0 (0%) 1 (0.8%) 0 (0%)
    Владимир 1 (<0.1%) 0 (0%) 1 (0.2%)
    Вологда 0 (0%) 0 (0%) 1 (0.2%)
    Волосово 1 (<0.1%) 0 (0%) 0 (0%)
    Воронеж 1 (<0.1%) 0 (0%) 1 (0.2%)
    Вострово 0 (0%) 0 (0%) 1 (0.2%)
    Воткинск 1 (<0.1%) 0 (0%) 0 (0%)
    Выдриха 1 (<0.1%) 1 (0.8%) 0 (0%)
    Горно-Алтайск 18 (0.9%) 0 (0%) 3 (0.6%)
    Горняк 2 (0.1%) 0 (0%) 0 (0%)
    Гурзуф 1 (<0.1%) 0 (0%) 0 (0%)
    Дербент 0 (0%) 0 (0%) 1 (0.2%)
    Дмитриевка 1 (<0.1%) 0 (0%) 0 (0%)
    Днепр (Днепропетровск) 1 (<0.1%) 0 (0%) 0 (0%)
    Донецк 1 (<0.1%) 0 (0%) 0 (0%)
    Дудинка 1 (<0.1%) 0 (0%) 0 (0%)
    Душанбе 1 (<0.1%) 0 (0%) 0 (0%)
    Екатеринбург 4 (0.2%) 0 (0%) 1 (0.2%)
    Енисейск 1 (<0.1%) 0 (0%) 0 (0%)
    Енисейское 1 (<0.1%) 0 (0%) 0 (0%)
    Завьялово 4 (0.2%) 1 (0.8%) 0 (0%)
    Закаменск 0 (0%) 0 (0%) 1 (0.2%)
    Заринск 12 (0.6%) 1 (0.8%) 2 (0.4%)
    Зеленоградск 0 (0%) 0 (0%) 1 (0.2%)
    Змеиногорск 1 (<0.1%) 1 (0.8%) 3 (0.6%)
    Зудилово 3 (0.2%) 0 (0%) 0 (0%)
    Зура 0 (0%) 0 (0%) 1 (0.2%)
    Игра 0 (0%) 0 (0%) 1 (0.2%)
    Иркутск 1 (<0.1%) 0 (0%) 1 (0.2%)
    Искитим 1 (<0.1%) 0 (0%) 0 (0%)
    Истиклол (Табошар) 1 (<0.1%) 0 (0%) 0 (0%)
    Ичня 0 (0%) 0 (0%) 1 (0.2%)
    Казань 2 (0.1%) 0 (0%) 1 (0.2%)
    Калининград 2 (0.1%) 0 (0%) 2 (0.4%)
    Калуга 1 (<0.1%) 0 (0%) 0 (0%)
    Камень-на-Оби 6 (0.3%) 0 (0%) 0 (0%)
    Канск 0 (0%) 0 (0%) 1 (0.2%)
    Караганда 1 (<0.1%) 0 (0%) 0 (0%)
    Касансай 1 (<0.1%) 0 (0%) 0 (0%)
    Кемерово 2 (0.1%) 0 (0%) 0 (0%)
    Киров 1 (<0.1%) 0 (0%) 0 (0%)
    Кладовка 1 (<0.1%) 0 (0%) 0 (0%)
    Комсомольск-на-Амуре 0 (0%) 0 (0%) 1 (0.2%)
    Кострома 1 (<0.1%) 0 (0%) 0 (0%)
    Кош-Агач 1 (<0.1%) 0 (0%) 0 (0%)
    Краснодар 2 (0.1%) 0 (0%) 0 (0%)
    Красноярск 2 (0.1%) 0 (0%) 1 (0.2%)
    Красный Партизан 0 (0%) 0 (0%) 1 (0.2%)
    Кубанка 0 (0%) 0 (0%) 1 (0.2%)
    Кулунда 3 (0.2%) 0 (0%) 0 (0%)
    Курган 0 (0%) 0 (0%) 1 (0.2%)
    Куюс 0 (0%) 0 (0%) 1 (0.2%)
    Кызыл 4 (0.2%) 2 (1.5%) 0 (0%)
    Кытманово 2 (0.1%) 0 (0%) 0 (0%)
    Ленинск-Кузнецкий 1 (<0.1%) 0 (0%) 0 (0%)
    Липецк 1 (<0.1%) 0 (0%) 0 (0%)
    Магадан 1 (<0.1%) 0 (0%) 0 (0%)
    Магнитогорск 0 (0%) 0 (0%) 1 (0.2%)
    Мамонтово 1 (<0.1%) 1 (0.8%) 3 (0.6%)
    Манжерок 0 (0%) 0 (0%) 1 (0.2%)
    Маслянино 1 (<0.1%) 0 (0%) 0 (0%)
    Междуреченск 3 (0.2%) 0 (0%) 0 (0%)
    Мир 1 (<0.1%) 0 (0%) 0 (0%)
    Могилёв 1 (<0.1%) 0 (0%) 0 (0%)
    Москва 39 (2.1%) 5 (3.8%) 19 (3.6%)
    Набережные Челны 0 (0%) 0 (0%) 1 (0.2%)
    Надым 1 (<0.1%) 0 (0%) 0 (0%)
    Нижнеангарск 1 (<0.1%) 0 (0%) 0 (0%)
    Нижневартовск 2 (0.1%) 0 (0%) 0 (0%)
    Николаев 1 (<0.1%) 0 (0%) 0 (0%)
    Новичиха 0 (0%) 0 (0%) 1 (0.2%)
    Новоалтайск 22 (1.2%) 4 (3.0%) 16 (3.1%)
    Новодвинск 0 (0%) 0 (0%) 2 (0.4%)
    Новоегорьевское 1 (<0.1%) 0 (0%) 0 (0%)
    Новокузнецк 5 (0.3%) 0 (0%) 1 (0.2%)
    Новомосковск 0 (0%) 0 (0%) 1 (0.2%)
    Новоперуново 1 (<0.1%) 0 (0%) 0 (0%)
    Новороссийск 1 (<0.1%) 0 (0%) 0 (0%)
    Новосибирск 43 (2.3%) 1 (0.8%) 20 (3.8%)
    Новоуткинск 0 (0%) 0 (0%) 1 (0.2%)
    Норильск 0 (0%) 0 (0%) 1 (0.2%)
    Омск 3 (0.2%) 0 (0%) 4 (0.8%)
    Орлеан 0 (0%) 0 (0%) 1 (0.2%)
    Отрадное 0 (0%) 0 (0%) 1 (0.2%)
    Павловск 4 (0.2%) 1 (0.8%) 1 (0.2%)
    Павловский Посад 1 (<0.1%) 0 (0%) 0 (0%)
    Павлодар 10 (0.5%) 1 (0.8%) 0 (0%)
    Партизанск 1 (<0.1%) 0 (0%) 0 (0%)
    Пенза 1 (<0.1%) 0 (0%) 0 (0%)
    Пермь 4 (0.2%) 0 (0%) 1 (0.2%)
    Петрозаводск 1 (<0.1%) 0 (0%) 1 (0.2%)
    Петропавловское 0 (0%) 0 (0%) 1 (0.2%)
    Победим 1 (<0.1%) 0 (0%) 0 (0%)
    Подольск 0 (0%) 0 (0%) 1 (0.2%)
    Подсосново 0 (0%) 0 (0%) 1 (0.2%)
    Покровка 0 (0%) 1 (0.8%) 0 (0%)
    Полковниково 0 (0%) 0 (0%) 1 (0.2%)
    Полысаево 1 (<0.1%) 0 (0%) 0 (0%)
    Порожнее 1 (<0.1%) 0 (0%) 0 (0%)
    Поспелиха 2 (0.1%) 0 (0%) 0 (0%)
    Поспелихинский 1 (<0.1%) 0 (0%) 0 (0%)
    Прокопьевск 4 (0.2%) 0 (0%) 0 (0%)
    Простоквашино 1 (<0.1%) 0 (0%) 0 (0%)
    Прутской 1 (<0.1%) 0 (0%) 0 (0%)
    Пушкино 1 (<0.1%) 0 (0%) 0 (0%)
    Развилка 1 (<0.1%) 0 (0%) 0 (0%)
    Рассыпное 1 (<0.1%) 0 (0%) 0 (0%)
    Ребриха 1 (<0.1%) 0 (0%) 0 (0%)
    Рига 2 (0.1%) 0 (0%) 0 (0%)
    Риддер 7 (0.4%) 0 (0%) 2 (0.4%)
    Родино 2 (0.1%) 0 (0%) 0 (0%)
    Романово 0 (0%) 0 (0%) 1 (0.2%)
    Ростов-на-Дону 0 (0%) 0 (0%) 1 (0.2%)
    Рубцовск 22 (1.2%) 2 (1.5%) 2 (0.4%)
    Рязань 1 (<0.1%) 0 (0%) 0 (0%)
    Самара 2 (0.1%) 0 (0%) 2 (0.4%)
    Санкт-Петербург 19 (1.0%) 2 (1.5%) 16 (3.1%)
    Севастополь 2 (0.1%) 0 (0%) 0 (0%)
    Северск 1 (<0.1%) 0 (0%) 0 (0%)
    Семей 15 (0.8%) 0 (0%) 0 (0%)
    Сибирский 1 (<0.1%) 0 (0%) 1 (0.2%)
    Симферополь 1 (<0.1%) 0 (0%) 0 (0%)
    Славгород 8 (0.4%) 1 (0.8%) 3 (0.6%)
    Смоленск 0 (0%) 0 (0%) 1 (0.2%)
    Советское 1 (<0.1%) 0 (0%) 0 (0%)
    Сочи 1 (<0.1%) 0 (0%) 2 (0.4%)
    Ставрополь 0 (0%) 0 (0%) 1 (0.2%)
    Староалейское 1 (<0.1%) 0 (0%) 0 (0%)
    Старобелокуриха 1 (<0.1%) 0 (0%) 0 (0%)
    Степное Озеро 1 (<0.1%) 0 (0%) 0 (0%)
    Сузун 1 (<0.1%) 0 (0%) 0 (0%)
    Сулея 1 (<0.1%) 0 (0%) 0 (0%)
    Сургут 4 (0.2%) 0 (0%) 1 (0.2%)
    Сухая Чемровка 1 (<0.1%) 0 (0%) 0 (0%)
    Талгар 1 (<0.1%) 0 (0%) 0 (0%)
    Тальменка 4 (0.2%) 1 (0.8%) 0 (0%)
    Ташкент 2 (0.1%) 0 (0%) 0 (0%)
    Тбилиси 2 (0.1%) 0 (0%) 0 (0%)
    Тверь 1 (<0.1%) 0 (0%) 0 (0%)
    Темиртау 1 (<0.1%) 0 (0%) 0 (0%)
    Тобольск 1 (<0.1%) 0 (0%) 0 (0%)
    Томск 9 (0.5%) 0 (0%) 3 (0.6%)
    Топольное 0 (0%) 0 (0%) 1 (0.2%)
    Топчиха 1 (<0.1%) 0 (0%) 1 (0.2%)
    Троицк 2 (0.1%) 0 (0%) 0 (0%)
    Троицкое 3 (0.2%) 1 (0.8%) 1 (0.2%)
    Турочак 0 (0%) 0 (0%) 1 (0.2%)
    Тюмень 3 (0.2%) 0 (0%) 1 (0.2%)
    Тяжинский 1 (<0.1%) 0 (0%) 0 (0%)
    Улан-Удэ 1 (<0.1%) 0 (0%) 0 (0%)
    Ульяновск 0 (0%) 0 (0%) 1 (0.2%)
    Усть-Илимск 1 (<0.1%) 0 (0%) 0 (0%)
    Усть-Каменогорск 1 (<0.1%) 0 (0%) 0 (0%)
    Усть-Кокса 0 (0%) 0 (0%) 1 (0.2%)
    Усть-Мосиха 0 (0%) 0 (0%) 1 (0.2%)
    Усть-Таловка 1 (<0.1%) 0 (0%) 0 (0%)
    Усть-Чарышская Пристань 1 (<0.1%) 0 (0%) 0 (0%)
    Уфа 2 (0.1%) 1 (0.8%) 0 (0%)
    Ухта 0 (0%) 0 (0%) 1 (0.2%)
    Уштобе 1 (<0.1%) 0 (0%) 0 (0%)
    Хабаровск 1 (<0.1%) 0 (0%) 1 (0.2%)
    Ханты-Мансийск 1 (<0.1%) 0 (0%) 1 (0.2%)
    Харьков 0 (0%) 1 (0.8%) 0 (0%)
    Хреново 1 (<0.1%) 0 (0%) 0 (0%)
    Худжанд 1 (<0.1%) 0 (0%) 0 (0%)
    Чарышское 0 (0%) 0 (0%) 1 (0.2%)
    Чебоксары 0 (0%) 0 (0%) 1 (0.2%)
    Челябинск 1 (<0.1%) 1 (0.8%) 1 (0.2%)
    Черепаново 1 (<0.1%) 0 (0%) 0 (0%)
    Черногорск 2 (0.1%) 0 (0%) 0 (0%)
    Чистоозерка 0 (0%) 0 (0%) 1 (0.2%)
    Чоя 1 (<0.1%) 0 (0%) 0 (0%)
    Шахты 1 (<0.1%) 0 (0%) 0 (0%)
    Шебалино 1 (<0.1%) 0 (0%) 1 (0.2%)
    Шемонаиха 3 (0.2%) 0 (0%) 0 (0%)
    Шипуново 0 (0%) 0 (0%) 3 (0.6%)
    Шушенское 1 (<0.1%) 0 (0%) 1 (0.2%)
    Южно-Сахалинск 1 (<0.1%) 0 (0%) 0 (0%)
    Яконур 1 (<0.1%) 0 (0%) 0 (0%)
    Яровое 7 (0.4%) 1 (0.8%) 0 (0%)
    Ярославцев Лог 0 (0%) 0 (0%) 1 (0.2%)
    Unknown 1,480 74 155
occupation_type


    Высшее образование 1,579 (69%) 103 (66%) 215 (54%)
    Работа 650 (28%) 50 (32%) 178 (44%)
    Среднее образование 63 (2.7%) 2 (1.3%) 8 (2.0%)
    Unknown 1,085 51 276
1 Median (IQR); n (%)

Самостоятельная работа

  1. По каждой группе сделать описательный анализ
  2. Свести все данные в одну обобщающую таблицу
  3. Описать, что получилось