Рубрики
Без рубрики

Наука о данных с помощью Python & R: Исследовательский анализ данных

В этой статье мы рассмотрим основные этапы процесса анализа данных Python и R.

Автор оригинала: Jose A Dianes.

Введение и получение обновления данных

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

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

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

Весь исходный код для различных частей этой серии учебных пособий и приложений можно проверить на GitHub . Не стесняйтесь участвовать и делиться с нами своими успехами!

Получение данных

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

Вопросы, на которые мы хотим ответить

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

  • Какие страны имеют самую высокую и инфекционную заболеваемость туберкулезом?
  • Какова общая мировая тенденция в период с 1990 по 2007 год?
  • Какие страны не следуют этой тенденции?
  • Какие еще факты о болезни мы знаем, которые мы можем проверить с помощью наших данных?

Описательная статистика

Питон

Метод описательной статистики основных данных для панды.DataFrame is description() . Это эквивалентно R data.frame function summary() .

df_summary = existing_df.describe()
df_summary
18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 считать 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000 18.000000
194.333333 413.444444 535.277778 36.944444 47.388889 25.277778 74.944444 28.055556 186.000000 означать 35.611111 282.666667 512.833333 61.222222 40.888889 128.888889 353.333333 12.277778 126.222222 43.388889 10.833333
52.158131 97.751318 91.975576 6.915220 4.487091 7.274497 16.129885 3.717561 62.027508 станд 1.243283 57.322616 113.411925 20.232634 2.422660 15.911109 64.708396 9.886447 86.784083 8.332353 2.812786
130.000000 281.000000 387.000000 22.000000 42.000000 17.000000 49.000000 23.000000 102.000000 минута 34.000000 220.000000 392.000000 35.000000 38.000000 102.000000 238.000000 0.000000 13.000000 31.000000 7.000000
146.750000 321.250000 459.000000 32.000000 44.000000 19.250000 62.000000 25.000000 128.750000 25% 35.000000 234.250000 420.750000 41.250000 39.000000 116.500000 305.000000 6.000000 63.250000 36.250000 9.000000
184.500000 399.000000 521.500000 40.500000 45.500000 22.500000 77.000000 27.500000 185.000000 50% 35.000000 257.000000 466.000000 60.500000 41.000000 131.500000 373.500000 9.000000 106.000000 43.000000 10.000000
248.500000 512.000000 620.000000 42.000000 50.750000 31.500000 85.750000 30.750000 240.000000 75% 36.000000 349.000000 616.750000 77.000000 42.000000 143.000000 404.500000 16.250000 165.750000 51.500000 12.750000
265.000000 530.000000 680.000000 44.000000 56.000000 39.000000 99.000000 35.000000 278.000000 максимум 38.000000 365.000000 714.000000 96.000000 46.000000 152.000000 436.000000 42.000000 352.000000 55.000000 16.000000
8 строк × 207 столбцов

Там очень много информации. Мы можем получить доступ к отдельным резюме следующим образом.

df_summary[['Spain','United Kingdom']]
18.000000 считать 18.000000
30.666667 означать 9.611111
6.677442 станд 0.916444
23.000000 минута 9.000000
25.250000 25% 9.000000
29.000000 50% 9.000000
34.750000 75% 10.000000
44.000000 максимум 12.000000

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

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

tb_pct_change_spain = existing_df.Spain.pct_change()
tb_pct_change_spain
    year
    1990         NaN
    1991   -0.045455
    1992   -0.047619
    1993   -0.075000
    1994   -0.054054
    1995   -0.028571
    1996   -0.029412
    1997   -0.090909
    1998    0.000000
    1999   -0.066667
    2000   -0.035714
    2001   -0.037037
    2002    0.000000
    2003   -0.038462
    2004   -0.040000
    2005    0.000000
    2006    0.000000
    2007   -0.041667
    Name: Spain, dtype: float64

И оттуда получите максимальное значение.

tb_pct_change_spain.max()
    0.0

И сделайте то же самое для Соединенного Королевства.

existing_df['United Kingdom'].pct_change().max()
    0.11111111111111116

Если мы хотим знать значение индекса (год), мы используем arg max (callex idmax в более поздних версиях Pandas) следующим образом.

existing_df['Spain'].pct_change().argmax()
    '1998'
existing_df['United Kingdom'].pct_change().argmax()
    '1992'

То есть 1998 и 1992 годы были худшими годами в Испании и Великобритании соответственно в отношении увеличения числа случаев инфекционного туберкулеза.

R

Основным методом описательной статистики в R является, как мы уже говорили, функция summary() .

existing_summary <- summary(existing_df)
str(existing_summary)
##  'table' chr [1:6, 1:207] "Min.   :238.0  " "1st Qu.:305.0  " ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : chr [1:6] "" "" "" "" ...
##   ..$ : chr [1:207] " Afghanistan" "   Albania" "   Algeria" "American Samoa" ...

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

existing_summary[,1]
##                                                                         
## "Min.   :238.0  " "1st Qu.:305.0  " "Median :373.5  " "Mean   :353.3  " 
##                                     
## "3rd Qu.:404.5  " "Max.   :436.0  "

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

data.frame(
    Spain=existing_summary[,which(colnames(existing_df)=='Spain')],
    UK=existing_summary[,which(colnames(existing_df)=='United Kingdom')])
##             Spain               UK
## 1 Min.   :23.00   Min.   : 9.000  
## 2 1st Qu.:25.25   1st Qu.: 9.000  
## 3 Median :29.00   Median : 9.000  
## 4 Mean   :30.67   Mean   : 9.611  
## 5 3rd Qu.:34.75   3rd Qu.:10.000  
## 6 Max.   :44.00   Max.   :12.000

Будучи R функциональным языком, мы можем применять такие функции, как sum , mean , sd и т. Д. к векторам. Помните, что фрейм данных-это список векторов (т. Е. Каждый столбец-это вектор значений), поэтому мы можем легко использовать эти функции со столбцами. Наконец, мы можем объединить эти функции с lapply или sapply и применить их к нескольким столбцам в фрейме данных.

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

Допустим, мы хотим получить среднее количество существующих случаев в год. Нам нужен один вызов функции.

rowMeans(existing_df)
##    X1990    X1991    X1992    X1993    X1994    X1995    X1996    X1997 
## 196.9662 196.4686 192.8116 191.1739 188.7246 187.9420 178.8986 180.9758 
##    X1998    X1999    X2000    X2001    X2002    X2003    X2004    X2005 
## 178.1208 180.4734 177.5217 177.7971 179.5169 176.4058 173.9227 171.1836 
##    X2006    X2007 
## 169.0193 167.2560

Построение

В этом разделе мы рассмотрим основные функции построения графиков в Python/Pandas и R. Однако существуют более мощные альтернативы, такие как ggplot2 , которые, хотя и изначально созданы для R, имеют свою собственную реализацию для Python от Yhat парней.

Питон

Фреймы данных Pandas реализуют до трех методов построения графиков из коробки (проверьте documentation ). Первый-это базовый линейный график для каждой серии, которую мы включаем в индексацию. Первая строка может потребоваться при построении графика при использовании IPython notebook.

%matplotlib inline

 existing_df[['United Kingdom', 'Spain', 'Colombia']].plot()
введите описание изображения здесь

Или мы можем использовать прямоугольники для получения обобщенного представления данного ряда следующим образом.

 existing_df[['United Kingdom', 'Spain', 'Colombia']].boxplot()
введите описание изображения здесь

Существует также метод histogram () , но мы не можем использовать его с этим типом данных прямо сейчас.

R

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

Давайте начнем с базовой линейной диаграммы, как мы делали с Python/Pandas.

uk_series <- existing_df[,c("United Kingdom")]
spain_series <- existing_df[,c("Spain")]
colombia_series <- existing_df[,c("Colombia")]
xrange <- 1990:2007
plot(xrange, uk_series, 
     type='l', xlab="Year", 
     ylab="Existing cases per 100K", 
     col = "blue", 
     ylim=c(0,100))
lines(xrange, spain_series, 
      col = "darkgreen")
lines(xrange, colombia_series,
      col = "red")
legend(x=2003, y=100, 
       lty=1, 
       col=c("blue","darkgreen","red"), 
       legend=c("UK","Spain","Colombia"))
введите описание изображения здесь

Вы можете сравнить, как легко было построить три серии в Pandas, и как выполнение того же самого с базовым построением в R становится более подробным. По крайней мере, нам нужно три вызова функций, для сюжета и линии, а затем у нас есть легенда и т. Д. Базовый график в R действительно предназначен для создания быстрых и грязных диаграмм.

Давайте теперь воспользуемся прямоугольными графиками.

boxplot(uk_series, spain_series, colombia_series, 
        names=c("UK","Spain","Colombia"),
        xlab="Year", 
        ylab="Existing cases per 100K")
введите описание изображения здесь

Этот был намного короче, и нам даже не нужны цвета или легенда.

Ответы на Вопросы

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

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

Питон

Если нам нужны только верхние, мы можем использовать apply и argmax . Помните, что по умолчанию apply работает со столбцами (в нашем случае со странами), и мы хотим применять его к каждому году. Поэтому нам нужно транспонировать фрейм данных перед его использованием, или мы можем передать аргумент axis=1 .

 existing_df.apply(pd.Series.argmax, axis=1)
    year
    1990            Djibouti
    1991            Djibouti
    1992            Djibouti
    1993            Djibouti
    1994            Djibouti
    1995            Djibouti
    1996            Kiribati
    1997            Kiribati
    1998            Cambodia
    1999    Korea, Dem. Rep.
    2000            Djibouti
    2001           Swaziland
    2002            Djibouti
    2003            Djibouti
    2004            Djibouti
    2005            Djibouti
    2006            Djibouti
    2007            Djibouti
    dtype: object

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

Мировые тенденции в случаях туберкулеза

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

deaths_total_per_year_df = deaths_df.sum(axis=1)
existing_total_per_year_df = existing_df.sum(axis=1)
new_total_per_year_df = new_df.sum(axis=1)

Теперь мы создадим новый фрейм данных с каждой суммой в серии, которую мы построим с помощью метода фрейма данных plot () .

world_trends_df = pd.DataFrame({
           'Total deaths per 100K' : deaths_total_per_year_df, 
           'Total existing cases per 100K' : existing_total_per_year_df, 
           'Total new cases per 100K' : new_total_per_year_df}, 
       index=deaths_total_per_year_df.index)
world_trends_df.plot(figsize=(12,6)).legend(
    loc='center left', 
    bbox_to_anchor=(1, 0.5))
введите описание изображения здесь

Похоже, что общая тенденция заключается в уменьшении общего числа существующих случаев на 100 тыс. Однако число новых случаев растет, хотя, по-видимому, оно возвращается с 2005 года. Так как же возможно, что общее число существующих случаев уменьшается, если общее число новых случаев растет? Одной из причин может быть наблюдаемое увеличение числа смертей на 100 тыс., но главная причина, которую мы должны учитывать, заключается в том, что люди выздоравливают от туберкулеза благодаря лечению. Сумма коэффициента выздоровления плюс коэффициент смертности больше, чем коэффициент новых случаев. В любом случае, кажется, что новых случаев больше, но и мы лучше их лечим. Нам необходимо улучшить профилактику и борьбу с эпидемиями.

Страны вне тенденции

Так что предыдущая была общей тенденцией мира в целом. Так какие же страны с другой тенденцией (к худшему)? Чтобы выяснить это, сначала нам нужно знать распределение смертей по странам в среднем за год.

deaths_by_country_mean = deaths_df.mean()
deaths_by_country_mean_summary = deaths_by_country_mean.describe()
existing_by_country_mean = existing_df.mean()
existing_by_country_mean_summary = existing_by_country_mean.describe()
new_by_country_mean = new_df.mean()
new_by_country_mean_summary = new_by_country_mean.describe()

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

deaths_by_country_mean.order().plot(kind='bar', figsize=(24,6))
введите описание изображения здесь

Мы хотим, чтобы эти страны выходили за пределы 1,5-кратного межквартильного диапазона (50%). У нас есть эти ценности в:

deaths_outlier = deaths_by_country_mean_summary['50%']*1.5
existing_outlier = existing_by_country_mean_summary['50%']*1.5
new_outlier = new_by_country_mean_summary['50%']*1.5

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

# Now compare with the outlier threshold
outlier_countries_by_deaths_index = 
    deaths_by_country_mean > deaths_outlier
outlier_countries_by_existing_index = 
   existing_by_country_mean > existing_outlier
outlier_countries_by_new_index = 
    new_by_country_mean > new_outlier

Какая доля стран у нас не в тренде? Для смертей:

num_countries = len(deaths_df.T)
sum(outlier_countries_by_deaths_index)/num_countries
    0.39613526570048307

Для существующих случаев (распространенность):

 sum(outlier_countries_by_existing_index)/num_countries
    0.39613526570048307

Для новых случаев (заболеваемость):

 sum(outlier_countries_by_new_index)/num_countries
    0.38647342995169082

Теперь мы можем использовать эти индексы для фильтрации наших исходных фреймов данных.

outlier_deaths_df = deaths_df.T[ outlier_countries_by_deaths_index ].T
outlier_existing_df = existing_df.T[ outlier_countries_by_existing_index ].T
outlier_new_df = new_df.T[ outlier_countries_by_new_index ].T

Это серьезные вещи. У нас более трети стран мира являются выбросами по распределению существующих случаев заболевания, новых случаев заболевания и смертей от инфекционного туберкулеза. Но что, если мы посчитаем, что выброс в 5 раз превышает IQR? Давайте повторим предыдущий процесс.

deaths_super_outlier = deaths_by_country_mean_summary['50%']*5
existing_super_outlier = existing_by_country_mean_summary['50%']*5
new_super_outlier = new_by_country_mean_summary['50%']*5
    
super_outlier_countries_by_deaths_index = 
    deaths_by_country_mean > deaths_super_outlier
super_outlier_countries_by_existing_index = 
    existing_by_country_mean > existing_super_outlier
super_outlier_countries_by_new_index = 
    new_by_country_mean > new_super_outlier

Какая доля у нас сейчас?

sum(super_outlier_countries_by_deaths_index)/num_countries
    0.21739130434782608

Давайте возьмем фреймы данных.

super_outlier_deaths_df = 
    deaths_df.T[ super_outlier_countries_by_deaths_index ].T
super_outlier_existing_df = 
    existing_df.T[ super_outlier_countries_by_existing_index ].T
super_outlier_new_df = 
    new_df.T[ super_outlier_countries_by_new_index ].T

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

super_outlier_new_df
год
308 540 258 167 163 297 184 1990 307 585 582 513 329 267 169 393 322 207 301 177 344
314 516 286 185 250 349 201 1991 341 579 594 503 364 266 188 386 322 220 301 196 344
320 492 314 197 272 411 218 1992 364 574 606 493 389 260 200 380 322 233 302 209 344
326 470 343 212 296 460 244 1993 390 568 618 483 417 267 215 373 322 248 305 224 344
333 449 373 225 306 501 280 1994 415 563 630 474 444 293 229 366 322 263 309 239 344
339 428 390 241 319 536 323 1995 444 557 642 464 474 337 245 360 322 279 317 255 344
346 409 389 254 314 554 362 1996 468 552 655 455 501 398 258 353 322 297 332 269 344
353 391 401 273 320 576 409 1997 503 546 668 446 538 474 277 347 322 315 360 289 344
360 373 412 294 326 583 461 1998 542 541 681 437 580 558 299 341 322 334 406 312 344
367 356 417 319 324 603 519 1999 588 536 695 428 628 691 324 335 322 355 479 338 344
374 340 425 348 340 602 553 2000 640 530 708 420 685 801 353 329 322 377 576 368 344
382 325 414 376 360 627 576 2001 692 525 722 412 740 916 382 323 322 400 683 398 344
389 310 416 402 386 632 613 2002 740 520 737 403 791 994 408 317 322 425 780 425 344
397 296 410 419 396 652 635 2003 772 515 751 396 825 1075 425 312 322 451 852 444 344
405 283 405 423 385 623 643 2004 780 510 766 388 834 1127 430 306 322 479 898 448 344
413 270 391 418 370 588 639 2005 770 505 781 380 824 1141 425 301 322 509 925 443 344
421 258 368 408 350 547 638 2006 751 500 797 372 803 1169 414 295 322 540 940 432 344
429 246 346 397 330 506 637 2007 731 495 813 365 782 1198 403 290 322 574 948 420 344
18 строк × 22 столбца

Давайте сделаем несколько сюжетов, чтобы получить лучшее впечатление.

super_outlier_new_df.plot(figsize=(12,4)).legend(loc='center left', bbox_to_anchor=(1, 0.5))
введите описание изображения здесь

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

average_super_outlier_country = super_outlier_new_df.mean(axis=1)
average_super_outlier_country
    year
    1990    314.363636
    1991    330.136364
    1992    340.681818
    1993    352.909091
    1994    365.363636
    1995    379.227273
    1996    390.863636
    1997    408.000000
    1998    427.000000
    1999    451.409091
    2000    476.545455
    2001    502.409091
    2002    525.727273
    2003    543.318182
    2004    548.909091
    2005    546.409091
    2006    540.863636
    2007    535.181818
    dtype: float64

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

avearge_better_world_country = 
    new_df.T[ - super_outlier_countries_by_new_index ].T.mean(axis=1)
avearge_better_world_country
    year
    1990    80.751351
    1991    81.216216
    1992    80.681081
    1993    81.470270
    1994    81.832432
    1995    82.681081
    1996    82.589189
    1997    84.497297
    1998    85.189189
    1999    86.232432
    2000    86.378378
    2001    86.551351
    2002    89.848649
    2003    87.778378
    2004    87.978378
    2005    87.086022
    2006    86.559140
    2007    85.605405
    dtype: float64

Теперь давайте сравним эту страну со средней страной мира.

two_world_df = 
    pd.DataFrame({ 
            'Average Better World Country': avearge_better_world_country,
            'Average Outlier Country' : average_super_outlier_country},
        index = new_df.index)
two_world_df.plot(title="Estimated new TB cases per 100K",figsize=(12,8))
введите описание изображения здесь

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

two_world_df.pct_change().plot(title="Percentage change in estimated new TB cases", figsize=(12,8))
введите описание изображения здесь

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

R

Мы уже знаем, что мы можем использовать max со столбцом фрейма данных в R и получить максимальное значение. Кроме того, мы можем использовать which.max для того, чтобы получить его позицию (аналогично использованию og argmax в Pandas). Если мы используем транспонированный фрейм данных, мы можем использовать lapply или sapply для выполнения этой операции в каждом столбце year, получая затем либо список, либо вектор индексов (мы будем использовать sapply , который возвращает вектор). Нам просто нужно немного подправить и использовать вектор стран, который мы будем индексировать, чтобы получить название страны вместо индекса в результате.

country_names <- rownames(existing_df_t)
sapply(existing_df_t, function(x) {country_names[which.max(x)]})
##              X1990              X1991              X1992 
##         "Djibouti"         "Djibouti"         "Djibouti" 
##              X1993              X1994              X1995 
##         "Djibouti"         "Djibouti"         "Djibouti" 
##              X1996              X1997              X1998 
##         "Kiribati"         "Kiribati"         "Cambodia" 
##              X1999              X2000              X2001 
## "Korea, Dem. Rep."         "Djibouti"        "Swaziland" 
##              X2002              X2003              X2004 
##         "Djibouti"         "Djibouti"         "Djibouti" 
##              X2005              X2006              X2007 
##         "Djibouti"         "Djibouti"         "Djibouti"
Мировые тенденции в случаях туберкулеза

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

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

# Download files
deaths_file <- getURL("https://docs.google.com/spreadsheets/d/12uWVH_IlmzJX_75bJ3IH5E-Gqx6-zfbDKNvZqYjUuso/pub?gid=0&output=CSV")
new_cases_file <- getURL("https://docs.google.com/spreadsheets/d/1Pl51PcEGlO9Hp4Uh0x2_QM0xVb53p2UDBMPwcnSjFTk/pub?gid=0&output=csv")

# Read into data frames
deaths_df <- read.csv(
    text = deaths_file, 
    row.names=1, 
    stringsAsFactor=F)
new_df <- read.csv(
    text = new_cases_file, 
    row.names=1, 
    stringsAsFactor=F)

# Cast data to int (deaths doesn't need it)
new_df[1:18] <- lapply(
    new_df[1:18], 
    function(x) { as.integer(gsub(',', '', x) )})

# Transpose
deaths_df_t <- deaths_df
deaths_df <- as.data.frame(t(deaths_df))
new_df_t <- new_df
new_df <- as.data.frame(t(new_df))

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

deaths_total_per_year_df <- data.frame(total=rowSums(deaths_df))
existing_total_per_year_df <- data.frame(total=rowSums(existing_df))
# We pass na.rm = TRUE in order to ignore missing values in the new
# cases data frame when summing (no missing values in other dataframes though)
new_total_per_year_df <- data.frame(total=rowSums(new_df, na.rm = TRUE))

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

xrange <- 1990:2007
plot(xrange, deaths_total_per_year_df$total, 
     type='l', xlab="Year", 
     ylab="Count per 100K", 
     col = "blue", 
     ylim=c(0,50000))
lines(xrange, existing_total_per_year_df$total,
      col = "darkgreen")
lines(xrange, new_total_per_year_df$total, 
      col = "red")
legend(x=1992, y=52000, 
       lty=1, 
       cex = .7,
       ncol = 3,
       col=c("blue","darkgreen","red"), 
       legend=c("Deaths","Existing cases","New cases"))
введите описание изображения здесь

Выводы, очевидно, те же, что и при использовании Python.

Страны вне тенденции

Итак, какие страны являются выбросами этой тенденции (к худшему)? Опять же, чтобы выяснить это, сначала нам нужно знать распределение стран в среднем за год. Для этой цели мы используем coleman .

deaths_by_country_mean <- data.frame(mean=colMeans(deaths_df))
existing_by_country_mean <- data.frame(mean=colMeans(existing_df))
new_by_country_mean <- data.frame(mean=colMeans(new_df, na.rm=TRUE))

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

barplot(sort(deaths_by_country_mean$mean))
введите описание изображения здесь

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

Давайте на этот раз пропустим часть с выбросами 1,5 и перейдем непосредственно к выбросам 5,0. В R мы будем использовать другой подход. Мы будем использовать функцию quantile () , чтобы получить межквартильный диапазон и определить порог выброса.

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

new_super_outlier <- 
    quantile(new_by_country_mean$mean, probs = c(.5)) * 5.0
super_outlier_countries_by_new_index <- 
    new_by_country_mean > new_super_outlier

И пропорция такова.

sum(super_outlier_countries_by_new_index)/208
## [1] 0.1057692

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

super_outlier_new_df <- 
    new_df[, super_outlier_countries_by_new_index ]

Теперь мы готовы их построить.

xrange <- 1990:2007
plot(xrange, super_outlier_new_df[,1], 
     type='l', xlab="Year", 
     ylab="New cases per 100K", 
     col = 1, 
     ylim=c(0,1800))
for (i in seq(2:ncol(super_outlier_new_df))) {
    lines(xrange, super_outlier_new_df[,i],
    col = i)
}
legend(x=1990, y=1800, 
       lty=1, cex = 0.5,
       ncol = 7,
       col=1:22,
       legend=colnames(super_outlier_new_df))
введите описание изображения здесь

Определенно, мы видим здесь преимущество использования базового построения Pandas по сравнению с базовым построением R!

Пока наши результаты совпадают. У нас есть 22 страны, где число новых случаев заболевания в среднем за год более чем в 5 раз превышает медианное значение распределения. Давайте создадим страну, которая в среднем представляет эти 22 страны. Мы будем использовать rowMeans() здесь.

average_countries_df <- 
    data.frame(
        averageOutlierMean=rowMeans(super_outlier_new_df, na.rm=T)
    )
average_countries_df
##       averageOutlierMean
## X1990           314.3636
## X1991           330.1364
## X1992           340.6818
## X1993           352.9091
## X1994           365.3636
## X1995           379.2273
## X1996           390.8636
## X1997           408.0000
## X1998           427.0000
## X1999           451.4091
## X2000           476.5455
## X2001           502.4091
## X2002           525.7273
## X2003           543.3182
## X2004           548.9091
## X2005           546.4091
## X2006           540.8636
## X2007           535.1818

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

average_countries_df$averageBetterWorldMean <- 
    rowMeans(new_df[ ,- super_outlier_countries_by_new_index ], na.rm=T)
average_countries_df
##       averageOutlierMean averageBetterWorldMean
## X1990           314.3636               105.2767
## X1991           330.1364               107.3786
## X1992           340.6818               108.0243
## X1993           352.9091               110.0388
## X1994           365.3636               111.6942
## X1995           379.2273               113.9369
## X1996           390.8636               115.0971
## X1997           408.0000               118.6408
## X1998           427.0000               121.2913
## X1999           451.4091               124.8350
## X2000           476.5455               127.6505
## X2001           502.4091               130.5680
## X2002           525.7273               136.0194
## X2003           543.3182               136.0388
## X2004           548.9091               136.8155
## X2005           546.4091               135.5121
## X2006           540.8636               134.4493
## X2007           535.1818               133.2184

Теперь давайте построим график страны-аутсайдера со средней страной мира.

xrange <- 1990:2007
plot(xrange, average_countries_df$averageOutlierMean, 
     type='l', xlab="Year", 
     ylab="New cases per 100K", 
     col = "darkgreen", 
     ylim=c(0,600))
lines(xrange, average_countries_df$averageBetterWorldMean, col = "blue")
legend(x=1990, y=600, 
       lty=1, cex = 0.7,
       ncol = 2,
       col=c("darkgreen","blue"),
       legend=c("Average outlier country", "Average World Country"))
введите описание изображения здесь

Поиск в Google о событиях и датах в Туберкулезе

В этом разделе мы будем использовать только Python. О гугле, на самом деле мы просто перешли прямо к Запись в Википедии об этой болезни . В разделах эпидемии мы обнаружили следующее:

  • Общее число случаев заболевания туберкулезом сокращается с 2005 года, в то время как новые случаи сократились с 2002 года.

  • Это подтверждается нашим предыдущим анализом.

  • Китай добился особенно значительного прогресса, снизив уровень смертности от туберкулеза примерно на 80% в период с 1990 по 2010 год. Давайте проверим это:

existing_df.China.plot(title="Estimated existing TB cases in China")
введите описание изображения здесь
  • В 2007 году страной с самым высоким, по оценкам, уровнем заболеваемости туберкулезом был Свазиленд-1200 случаев на 100 000 человек.
new_df.apply(pd.Series.argmax, axis=1)['2007']
    'Swaziland'

Есть еще много выводов Википедии, которые мы можем подтвердить с помощью тех или иных наборов данных из Gapminder world. Например, туберкулез и ВИЧ часто ассоциируются с уровнем бедности. Было бы интересно объединить наборы данных и изучить тенденции в каждом из них. Мы призываем читателя попробовать и поделиться с нами своими выводами.

Другие веб – страницы для изучения

Некоторые интересные ресурсы о туберкулезе помимо веб-сайта Gapminder:

  • Фундамент ворот:
  • Фундамент ворот:
  • Фундамент ворот:

Выводы

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

Традиционно R был предпочтительным оружием для большинства работ EDA, хотя использование более выразительной библиотеки построения графиков, такой как gglot2, довольно удобно. Фактически, базовая функциональность построения графиков, включенная в Pandas, делает процесс более чистым и быстрым при использовании Python. Однако вопросы, на которые мы ответили здесь, были очень простыми и не включали в себя несколько переменных и кодировок. В таких случаях будет сиять продвинутая библиотека, такая как ggplot2. Помимо предоставления более приятных диаграмм, он сэкономит нам довольно много времени благодаря своей выразительности и возможности повторного использования.

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

Помните, что весь исходный код для различных частей этой серии учебных пособий и приложений можно проверить на GitHub . Не стесняйтесь участвовать и делиться с нами своими успехами!