Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Mastitsky_and_Shitikov_2014.pdf
Скачиваний:
177
Добавлен:
25.12.2019
Размер:
10.99 Mб
Скачать

возникших

из-за

неудачного

планирования

эксперимента(см. выше

пример

с

температурой), может быть иногда вполне оправданным. Оправданным будет также

 

удаление выбросов, возникших из-за явных ошибок при выполнении измерений.

 

 

В то же время, необычные наблюдения среди значений зависимой переменной

могут потребовать более тонкого подхода, особенно если они отражают естественную

 

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

 

условий, в которых происходила

экспериментальная часть исследования– это может

 

помочь интерпретировать "выбросы" в ходе анализа данных. Независимо от причин

 

возникновения необычных наблюдений, в итоговом научном отчете (например,

в статье)

 

важно сообщить читателю, как о самом факте выявления таких наблюдений, так и о

 

принятых в их отношении мерах.

 

 

 

 

4.4.Заполнение пропущенных значений в таблицах данных

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

Несмотря на то, что книги по статистике скупо разбирают проблему исследования недостающих данных, в этой области существует впечатляющее множество подходов, методологий и их критических анализов(см. классическую монографию Little, Rubin, 2002). На практике процедура "борьбы с пропусками" обычно включает следующие шаги:

1.Идентификация недостающих данных.

2.Исследование закономерностей появления отсутствующих значений.

3.Формирование наборов данных, не содержащих пропуски (в результате удаления или замены соответствующих фрагментов).

Необходимо признать, что идентификация недостающих данных является здесь единственным однозначным шагом. Анализ, почему данные отсутствуют, зависит от вашего понимания процессов, которые воспроизводят экспериментальную информацию. Решение о способе устранения пропущенных значений также будет зависеть от вашей оценки того, какие процедуры приведут к самым надежным и точным результатам. Мы лишь бегло остановимся на некоторых функциях пакета mice, который является хорошим средством реализации всех шагов упомянутой процедуры (Kabacoff, 2011).

Для конкретизации наших дальнейших рассуждений рассмотрим набор данных sleep из пакетаVIM, составленный по результатам наблюдений за процессом сна62 млекопитающих разных видов(Allison, Chichetti, 1976). Авторы заинтересовались тем, почему потребность в сне у животных меняется от вида к виду и от каких экологических и таксономических переменных она зависит. Зависимые переменные включали продолжительность сна со сновидениями (Dream), сна без сновидений (NonD), и их сумма

(sleep). Таксономические переменные включали массу тела(BodyWgt), вес мозга (BrainWgt), продолжительность жизни (Span) и время беременности (Gest). Экологические переменные состояли 5из-бальных оценок степени хищничества животных (Pred), меры защищенности их места для сна (Exp), изменяющегося от глубокой норы до полностью открытого пространства, и показателя риска(Danger), который основывался на логической комбинации остальных двух (Pred и Exp).

Идентификация пропущенных значений обычно легко делается с использованием функций is.na() и complete.cases():

106

data(sleep, package="VIM") head(sleep)

1

BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger

6654.000

5712.0

NA

NA

3.3

38.6

645

3

5

3

2

1.000

6.6

6.3

2.0

8.3

4.5

42

3

1

3

3

3.385

44.5

NA

NA

12.5

14.0

60

1

1

1

4

0.920

5.7

NA

NA

16.5

NA

25

5

2

3

5

2547.000

4603.0

2.1

1.8

3.9

69.0

624

3

5

4

#список строк, в которых нет пропущенных значений sleep[complete.cases(sleep),]

#список строк, в которых хотя бы одно пропущенное значение sleep[!complete.cases(sleep),]

sum(is.na(sleep$Dream)) [1] 12

Таким образом, мы имеем 42 полностью укомплектованные строки и20 строк, имеющих хотя бы одно пропущенное значение. Из них 12 недостающих значений принадлежит переменной Dream.

Дополнительную статистическую информацию о пропусках предоставляет функция md.pattern(), а функции aggr(), matrixplot() и scattMiss() позволяют отобразить на графиках закономерности во встречаемости отсутствующих наблюдений:

 

library(mice)

 

 

 

 

 

 

 

 

 

 

 

md.pattern(sleep)

 

 

 

 

 

 

 

 

 

42

BodyWgt BrainWgt Pred Exp Danger Sleep Span Gest Dream NonD

0

1

1

1

1

1

1

1

1

1

1

2

1

1

1

1

1

1

0

1

1

1

1

3

1

1

1

1

1

1

1

0

1

1

1

9

1

1

1

1

1

1

1

1

0

0

2

2

1

1

1

1

1

0

1

1

1

0

2

1

1

1

1

1

1

1

0

0

1

1

2

2

1

1

1

1

1

0

1

1

0

0

3

1

1

1

1

1

1

1

0

1

0

0

3

 

0

0

0

0

0

4

4

4

12

14 38

Значения 0 в теле приведенной таблицы соответствуют недостающим значениям, причем в первой строке пропусков нет, а последующие строки упорядочены по числу их появления. Первый столбец указывает число случаев в каждом образце ,данных последний столбец – число переменных с отсутствующими значениями в каждой строке. Например, в четвертой строке в исходных данных содержится9 случаев с одновременно отсутствующими NonD и Dream. Набор данных содержит в общей сложности (42´0) + (2´1) + … + (1´3) = 38 недостающих значений, а в последней строке приведена частота пропусков для каждой переменной.

На диаграмме, полученной при помощи функции matrixplot(), числовые данные масштабируются к интервалу[0, 1] и представлены уровнями шкалы яркости, причем более темные цветами показаны большие значения. По умолчанию, недостающие значения представлены красным цветом. График является интерактивным: нажатие на столбец отсортирует матрицу по этой переменной(на рисунке – в порядке убывания

BodyWgt). matrixplot(sleep)

107

 

60

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

50

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Index

40

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

30

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

20

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

10

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BodyWgt

BrainWgt

NonD

Dream

Sleep

Span

Gest

Pred

Exp

Danger

Такая визуализация позволяет увидеть, связаны ли пропуски одной или более переменных с фактическими значениями других признаков. Например: при низких значениях массы тела или мозга(BodyWgt, BrainWgt) пропуски переменных сна (Dream, NonD) отсутствуют. Количественно эти зависимости можно установить, рассчитав коэффициенты корреляции исходных переменных с частотами пропущенных значений:

#Формируем матрицу со значениями 1 в местах пропусков

x<- as.data.frame (abs (is.na (sleep)))

y<- x[, which(colSums(x) > 0)]

print(cor(y),4)

Dream

Sleep

Span

Gest

NonD

NonD

1.0000

0.90711

0.48626

0.01520

-0.14183

Dream

0.9071

1.00000

0.20370

0.03752

-0.12865

Sleep

0.4863

0.20370

1.00000

-0.06897 -0.06897

Span

0.0152

0.03752

-0.06897 1.00000 0.19828

Gest

-0.1418 -0.12865 -0.06897

0.19828

1.00000

Корреляционная матрица между частотами пропусков показывает, что появление недостающих значений для NonD и Dream взаимосвязано (r = 0.9071). Это естественно: если мы имеем фактическое значение одной из этих переменных, мы можем рассчитать другое с использованием алгебраического соотношения NonD + Dream = Sleep.

cor(sleep, y, use="pairwise.complete.obs")

Gest

BodyWgt

NonD

Dream

Sleep

Span

0.22683

0.22259

0.001685

-0.05832 -0.05397

BrainWgt 0.17946 0.16321 0.007859 -0.07921 -0.07333

NonD

NA

NA

NA -0.04315

-0.04553

Dream

-0.18895

NA -0.188952

0.11699

0.22775

108

Sleep

-0.08023 -0.08023

NA

0.09638

0.03976

Span

0.08336

0.05981

0.005239

NA -0.06527

Gest

0.20239

0.05140

0.159702

-0.17495

NA

Pred

0.04758

-0.06834

0.202463

0.02314

-0.20102

Exp

0.24547

0.12741

0.260773

-0.19292 -0.19292

Danger

0.06528

-0.06725

0.208884

-0.06666

-0.20444

В первом столбце этой корреляционной матрицы можно заметить, что частота пропусков регистрации сна без сновидений с большей вероятностью связана с высоким весом тела BodyWgt (r = 0.227), продолжительностью беременности Gest (r = 0.202) и защищенностью лежбища Exp (0.245).

На использовании корреляционных отношений основан популярный метод заполнения пропусков с использованием регрессионных моделей. Другой подход, называемый "множественное присвоение" (multiple imputation), основан на многократно повторяющемся моделировании данных с использованием методов Монте-Карло.

Функция mice() из одноименного пакета реализует метод Гиббса (Gibbs sampler), который представляет собой способ формирования выборок(x1; …; xn) из заданных распределений p(x) m-мерных переменных путем многократного извлечения имитируемых значений. По умолчанию, каждая переменная, содержащая недостающие величины, моделируется в зависимости от всех других переменных в наборе данных. Полученные уравнения предсказания используются, чтобы приписать наиболее вероятные значения для пропущенных данных. Процесс повторяется, пока не будет достигнут определенный

критерий сходимости. Для каждой

переменной

пользователь

может

выбрать форму

модели предсказания, называемую элементарным методом присвоения.

 

 

 

Процесс заполнения пропусков реализуется в несколько этапов:

 

 

°

функция

mice()

обрабатывает mydata

матрицу или структуру данных,

 

содержащую недостающие значения, и возвращает объект imp, содержащий несколько

 

полных наборов данных (например, m = 5), отличающихся между собой значениями

 

пропусков, заполненных в ходе процедуры Гиббса, но с включением некоторого

 

случайного компонента:

 

 

 

 

 

 

 

imp <- mice(mydata, m)

 

 

 

 

 

 

°

функция

with()

используется, чтобы

применить

статистическую

модель

 

analysis к каждому набору данных изimp; это может быть линейнаяlm() или

 

обобщенная

линейная glm() модели, аддитивная

модель gam() или

любая

иная,

 

задаваемая пользователем:

 

 

 

 

 

 

 

fit <- with(imp, analysis)

 

 

 

 

 

°

функция pool()

комбинирует

результаты

и

объединяет их в

заключительную

модель, в которой стандартные ошибки иp-значения сбалансированы относительно неопределенности, порожденной пропусками:

pooled <- pool(fit)

° наконец, функция complete() создает набор данных с заполненными пропусками: complete(imp, action=#)

Применим процедуру множественного присвоения к набору данных sleep:

imp <- mice(sleep, seed=1234)

fit <- with(imp, lm(Dream ~ Span + Gest)) pooled <- pool(fit)

summary(pooled)

109

По результатам анализа моделей из объектаpooled можно установить, что показатель Dream статистически значимо зависит от переменнойGest, тогда как его зависимость от Span незначима. Исследуя объекты, созданные в ходе анализа, можно получить дополнительную информацию о процессе восстановления отсутствующих наблюдений. Например, рассмотрев данные объектаimp, можно установить, что восстановлены отсутствующие значения для следующих показателей:

NonD Dream Sleep

5

Span

Gest

3

4

6

7

"pmm" "pmm" "pmm" "pmm" "pmm"

причем для этого использовался метод"pmm" – "средних относительно предикторов" (predictive mean matching). В нашем примере метод заполнения пропусков был выбран по умолчанию, но пользователь может самостоятельно задать любой иной алгоритм 19из возможных c помощью параметра method функции mice().

Для конкретного восстанавливаемого показателя в каждом из пяти имитируемых наборов данных мы можем посмотреть и проанализировать результаты расчетов:

imp$imp$Dream

1 2 3 4 5

1 0.5 0.5 0.5 0.5 0.0

32.3 2.4 1.9 1.5 2.4

41.2 1.3 5.6 2.3 1.3

140.6 1.0 0.0 0.3 0.5

241.2 1.0 5.6 1.0 6.6

261.9 6.6 0.9 2.2 2.0

301.0 1.2 2.6 2.3 1.4

315.6 0.5 1.2 0.5 1.4

470.7 0.6 1.4 1.8 3.6

530.7 0.5 0.7 0.5 0.5

550.5 2.4 0.7 2.6 2.6

621.9 1.4 3.6 5.6 6.6

 

Наконец, мы

можем

сохранить

любой

5изполных

наборов

данных

для

дальнейшего использования (например, нам понравился набор №3):

 

 

 

sleep_imp3 <- complete(imp, action=3)

 

 

 

 

 

head(sleep_imp3)

 

 

 

 

 

 

 

 

1

BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger

6654.000

5712.0

2.1

0.5

3.3

38.6

645

3

5

3

2

1.000

6.6

6.3

2.0

8.3

4.5

42

3

1

3

3

3.385

44.5

10.6

1.9

12.5

14.0

60

1

1

1

4

0.920

5.7

11.0

5.6

16.5

4.7

25

5

2

3

5

2547.000

4603.0

2.1

1.8

3.9

69.0

624

3

5

4

sleep[!complete.cases(sleep_imp3),] save(sleep_imp3, file="sleep_imp.Rdata")

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

Среда R поддерживает также несколько других подходов для восстановления недостающих данных. В иных обстоятельствах могут быть весьма полезными функции

mitools(), pan(), mix()

из

одноименных

пакетов, aregImpute() и

transcan() из пакета Hmisc и др.

 

 

 

110

4.5. Воспроизводимость результатов при использовании генератора случайных чисел

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

Всистеме R реализован целый ряд алгоритмов, позволяющих генерировать

случайные числа (см. ? RNGkind); по умолчанию используется один из наиболее быстрых генераторов – так называемый "вихрь Мерсенна" (Mersenne twister). Очень важно понимать, что практически все эти алгоритмы детерминированы, и поэтому генерируемые с их помощью числа правильнее называть "псевдослучайными".

Генератор псевдослучайных чисел (ГПСЧ) начинает свою работу с определенной точки в пространстве возможных чисел. Эта точка называется начальным числом (англ. seed). В R имеется возможность зафиксировать это число , такчто при повторном использовании ГПСЧ будет генерироваться точно та же последовательность чисел, что и в первый раз. Это может оказаться полезным в случаях, когда исследователь (по тем или иным причинам) желает иметь точную воспроизводимость результатов, получаемых с использованием ГПСЧ.

В качестве примера создадим таблицуexample с двумя столбцами. В первом столбце будут храниться коды уровней гипотетического фактораFactor (три уровня: A, B, и C). Для каждого из этих уровней сгенерируем (псевдо-)случайным образом по 300 нормально распределенных значений с разными средними и стандартными отклонениями:

example = data.frame(

Factor = rep(c("A", "B", "C"), each = 300), Variable = c(rnorm(300, 5, 2), rnorm(300, 4, 3),

rnorm(300, 2, 1))) tapply(example$Variable, example$Factor, summary)

$A

 

Median

Mean 3rd Qu.

Max.

Min. 1st Qu.

-0.9135

3.5950

5.0190

4.8520

6.2250

10.4900

$B

 

Median

Mean 3rd Qu.

Max.

Min. 1st Qu.

-4.407

2.194

4.226

4.028

5.962

13.750

$C

 

Median

Mean 3rd Qu.

Max.

Min. 1st Qu.

-0.517

1.365

1.997

1.975

2.582

4.458

Для построения графика используем ggplot2 – популярный графический пакет для R. Чтобы изобразить на одном графике кривые плотности вероятности для каждой из трех групп А, В, и С, выполним следующий код:

library(ggplot2)

p <- ggplot(example, aes(x = Variable))

(p <- p + geom_density(aes(fill = Factor), alpha = 1/2))

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

111

распределения для четырех повторностей таблицыexample, созданных при помощи ГПСЧ.

Кривые распределения четырех повторностей случайно генерируемых значений

а) без фиксации начального числа генератора случайных чисел

б) установлено начальное значение генератора случайных чисел set.seed(1020)

112