создание кадра данных из 5 случайно выбранных наблюдений

В настоящее время я читаю «Практическую статистику для специалистов по данным» и слежу за R, поскольку они демонстрируют некоторый код. Есть один кусок кода, который я особенно изо всех сил пытаюсь следовать логике, и надеялся, что кто-то может помочь. Рассматриваемый код создает фрейм данных с 1000 строками, где каждое наблюдение является средним значением 5 случайно выбранных значений дохода из фрейма данных loans_income. Однако я запутался в логике кода, поскольку он довольно сложен с функцией tapply() и вложенными операторами rep().

Код для создания рассматриваемого фрейма данных выглядит следующим образом:

samp_mean_5 <- data.frame(income = tapply(sample(loans_income$income,1000*5),
                                          rep(1:1000,rep(5,1000)),
                                          FUN = mean),
           type='mean_of_5')

В частности, меня смущают вложенные операторы rep() и часть 1000*5 функции sample(). Любая помощь в понимании логики кода будет принята с благодарностью!

Для справки: исходный набор данных loans_income содержит всего один столбец с 50 000 значений дохода.


person cliftjc1    schedule 11.06.2020    source источник


Ответы (1)


У вас есть 50 000 кредитов_дохода в одном векторе. Давайте разберем ваш код:

tapply(sample(loans_income$income,1000*5),
       rep(1:1000,rep(5,1000)),
       FUN = mean)

Я заменю 1000 на 10, а доход на случайные числа, чтобы было проще объяснить. Я также установил set.seed(1), чтобы результат можно было воспроизвести.

  1. sample(loans_income$income,1000*5)
    Мы 50 случайных доходов от вашего вектора без замены. Они (временно) помещаются в вектор длиной 50, поэтому вывод выглядит следующим образом:
> sample(runif(50000),10*5)
 [1] 0.73283101 0.60329970 0.29871173 0.12637654 0.48434952 0.01058067 0.32337850
 [8] 0.46873561 0.72334215 0.88515494 0.44036341 0.81386225 0.38118213 0.80978822
[15] 0.38291273 0.79795343 0.23622492 0.21318431 0.59325586 0.78340477 0.25623138
[22] 0.64621658 0.80041393 0.68511759 0.21880083 0.77455662 0.05307712 0.60320912
[29] 0.13191926 0.20816298 0.71600799 0.70328349 0.44408218 0.32696205 0.67845445
[36] 0.64438336 0.13241312 0.86589561 0.01109727 0.52627095 0.39207860 0.54643661
[43] 0.57137320 0.52743012 0.96631114 0.47151170 0.84099503 0.16511902 0.07546454
[50] 0.85970500
  1. rep(1:1000,rep(5,1000))
    Теперь мы создаем вектор индексации длиной 50:
> rep(1:10,rep(5,10))
[1]  1  1  1  1  1  2  2  2  2  2  3  3  3  3  3  4  4  4  4  4  5  5  5  5  5  6  6  6
[29]  6  6  7  7  7  7  7  8  8  8  8  8  9  9  9  9  9 10 10 10 10 10

Эти индексы «группируют» выборки из шага 1. Таким образом, в основном этот вектор сообщает R, что первые 5 записей вашего «вектора выборки» принадлежат друг другу (индекс 1), следующие 5 записей принадлежат друг другу (индекс 2) и так далее.

  1. FUN = mean
    Просто примените к данным функцию mean.

  2. tapply
    Итак, tapply берет выборочные данные (sample-часть) и группирует их по второму аргументу (rep()-часть) и применяет mean-функцию к каждой группе.

Если вы знакомы с data.frames и пакетом dplyr, взгляните на это (отображаются только первые 10 строк):

set.seed(1)
df <- data.frame(income=sample(runif(5000),10*5), index=rep(1:10,rep(5,10)))
       income index
1  0.42585569     1
2  0.16931091     1
3  0.48127444     1
4  0.68357403     1
5  0.99374923     1
6  0.53227877     2
7  0.07109499     2
8  0.20754511     2
9  0.35839481     2
10 0.95615917     2

Я прикрепил индекс к случайным числам (ваш income). Теперь вычисляем среднее значение по группе:

df %>% 
  group_by(index) %>%
  summarise(mean=mean(income))

что дает нам

# A tibble: 10 x 2
   index  mean
   <int> <dbl>
 1     1 0.551
 2     2 0.425
 3     3 0.827
 4     4 0.391
 5     5 0.590
 6     6 0.373
 7     7 0.514
 8     8 0.451
 9     9 0.566
10    10 0.435

Сравните это с

set.seed(1)
tapply(sample(runif(5000),10*5),
       rep(1:10,rep(5,10)),
       mean)

что дает в основном тот же результат:

        1         2         3         4         5         6         7         8         9 
0.5507529 0.4250946 0.8273149 0.3905850 0.5902823 0.3730092 0.5143829 0.4512932 0.5658460 
       10 
0.4352546
person Martin Gal    schedule 11.06.2020
comment
Благодарю за ваш ответ. (1.) Существует ли какое-либо соглашение для ввода «1000*5» в качестве второго аргумента функции-примера вместо простого ввода «5000»? (или 50, в вашем примере) - person cliftjc1; 12.06.2020
comment
(2.) Какой аргумент функции rep() удовлетворяет второму, вложенному rep()? Глядя на документацию, это аргумент «times»? Я понимаю, что общая цель этого шага — создать вектор индексации, но я думаю, что изо всех сил пытаюсь понять, как он это делает. - person cliftjc1; 12.06.2020
comment
Я собирался погрузиться в пакет dplyr, так как пока имею о нем довольно поверхностное представление. Но выглядит невероятно полезно! Спасибо за предложение - person cliftjc1; 12.06.2020
comment
@cliftjc1 (1) Я не знаю никаких соглашений. Я предполагаю, что выполнение 1000*5 должно явно показывать, что вы рисуете каждые 5 образцов для 1000 наблюдений. Разделение на 1000*5 позволяет вам проще заменить его (в целях моделирования) на n*m с переменным количеством выборок и наблюдений. - person Martin Gal; 12.06.2020
comment
(2) Второй аргумент rep() — это аргумент времени. Таким образом, для каждой записи первого аргумента он содержит количество повторений (в данном случае: каждая запись будет повторяться 5 раз). Взгляните на rep(1:10, 1:10). - person Martin Gal; 12.06.2020
comment
(3) dplyr-пакет, весь tidyverse-пакет, включая tidyr, stringr, ggplot2, действительно потрясающий и стоит того, чтобы его использовали и понимали. Этот сумасшедший %>% стиль кодирования (имхо) облегчает чтение кода, и мне это очень нравится. - person Martin Gal; 12.06.2020
comment
И последнее, но не менее важное: не стесняйтесь принимать ответ, если вы нашли его полезным. Просто нажмите на галочку рядом с ответом. - person Martin Gal; 12.06.2020
comment
Другой вопрос. Поскольку мы выбираем случайные образцы дохода, есть ли какая-либо функциональная разница между выполнением tapply(sample(loans_income$income,1000*5), rep(1:10,rep(5,10)), FUN = mean) и tapply(sample(loans_income$income,1000*5), rep(1:10,times=50), FUN = mean)? - person cliftjc1; 15.06.2020
comment
rep(1:10,rep(5,10)) создает вектор, подобный 1,1,1,1,1,2,2,2,2,2,3,...,10, тогда как rep(1:10,50) создает вектор, подобный 1,2,3,4,5,6, 7,8,9,10,1,2,3,4,5,....,10. С точки зрения проблемы (которая показывает, как с помощью выборки CLT распределения средних значений становятся более нормальными при больших размерах выборки), нет никакой разницы, верно? мы просто получаем разные средние значения, поскольку мы группируем разные доходы, используя разные векторы индексации. - person cliftjc1; 15.06.2020
comment
В этом случае я не вижу никакой реальной разницы между двумя способами. - person Martin Gal; 16.06.2020
comment
Потрясающий! Я проверил это, построив гистограммы двумя разными способами, и пришел к тому же выводу, что и вы! еще раз спасибо - person cliftjc1; 16.06.2020