Я хочу сделать случайную выборку из своего набора данных, используя разные пропорции для каждого значения факторной переменной, а также используя веса, хранящиеся в каком-то другом столбце. dplyr
решение в каналах будет предпочтительнее, так как его можно легко вставить в длинный код.
Давайте возьмем пример набора данных iris
. Species
столбец разбит на три значения по 50 строк в каждом. Предположим также, что веса выборки хранятся в столбце Sepal.Length
. Если мне нужно отобрать равные пропорции (или равные ряды) для каждого вида, проблему легко решить.
library(tidyverse)
iris %>% group_by(Species) %>% slice_sample(prop = 0.1, weight_by = Sepal.Length)
# A tibble: 15 x 5
# Groups: Species [3]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl> <dbl> <dbl> <dbl> <fct>
1 5.4 3.7 1.5 0.2 setosa
2 5.3 3.7 1.5 0.2 setosa
3 5.7 4.4 1.5 0.4 setosa
4 5 3.5 1.6 0.6 setosa
5 4.8 3.1 1.6 0.2 setosa
6 6.1 2.9 4.7 1.4 versicolor
7 6.7 3.1 4.7 1.5 versicolor
8 5 2 3.5 1 versicolor
9 7 3.2 4.7 1.4 versicolor
10 5.7 2.9 4.2 1.3 versicolor
11 7.2 3.2 6 1.8 virginica
12 6.7 2.5 5.8 1.8 virginica
13 6.4 2.8 5.6 2.1 virginica
14 6.3 3.3 6 2.5 virginica
15 7.2 3 5.8 1.6 virginica
Но я застрял, когда мне пришлось выбирать/пробовать разные пропорции для каждого вида, скажем, 10%, 20%, 25% соответственно.
iris %>% group_by(Species) %>% slice_sample(prop = c(0.1, 0.2, 0.25), weight_by = Sepal.Length)
#Error: `prop` must be a single number
ИЛИ
iris %>% group_split(Species) %>% map_df(c(0.1, 0.2, 0.25), ~ slice_sample(prop = ., weight_by = Sepal.Length))
# A tibble: 0 x 0
Пожалуйста помоги
Если я правильно тебя понял:
iris %>%
group_split(Species) %>%
map2(c(0.1, 0.2, 0.25), ~ slice_sample(.x, prop = .y))
[[1]]
# A tibble: 5 x 5
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl> <dbl> <dbl> <dbl> <fct>
1 4.9 3 1.4 0.2 setosa
2 4.8 3 1.4 0.1 setosa
3 5.2 4.1 1.5 0.1 setosa
4 5 3.5 1.6 0.6 setosa
5 5.2 3.5 1.5 0.2 setosa
[[2]]
# A tibble: 10 x 5
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl> <dbl> <dbl> <dbl> <fct>
1 6.3 2.5 4.9 1.5 versicolor
2 5.5 2.6 4.4 1.2 versicolor
3 6.9 3.1 4.9 1.5 versicolor
4 6.6 2.9 4.6 1.3 versicolor
5 6.1 3 4.6 1.4 versicolor
6 5.7 2.8 4.5 1.3 versicolor
7 6.7 3.1 4.4 1.4 versicolor
8 5.1 2.5 3 1.1 versicolor
9 5.7 3 4.2 1.2 versicolor
10 7 3.2 4.7 1.4 versicolor
[[3]]
# A tibble: 12 x 5
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl> <dbl> <dbl> <dbl> <fct>
1 6.4 3.2 5.3 2.3 virginica
2 7.2 3.2 6 1.8 virginica
3 6.3 3.3 6 2.5 virginica
4 6.2 2.8 4.8 1.8 virginica
5 7.6 3 6.6 2.1 virginica
6 5.7 2.5 5 2 virginica
7 4.9 2.5 4.5 1.7 virginica
8 6.7 3.1 5.6 2.4 virginica
9 7.7 2.8 6.7 2 virginica
10 6.7 3.3 5.7 2.5 virginica
11 6 3 4.8 1.8 virginica
12 5.6 2.8 4.9 2 virginica
Просто измените map2
на map2_df
, если вы хотите вернуть фрейм данных:
iris %>%
group_split(Species) %>%
map2_df(c(0.1, 0.2, 0.25), ~ slice_sample(.x, prop = .y))
# A tibble: 27 x 5
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl> <dbl> <dbl> <dbl> <fct>
1 5.7 3.8 1.7 0.3 setosa
2 4.8 3.1 1.6 0.2 setosa
3 5.1 3.8 1.5 0.3 setosa
4 4.9 3.6 1.4 0.1 setosa
5 4.8 3.4 1.6 0.2 setosa
6 5.7 2.8 4.1 1.3 versicolor
7 6.6 3 4.4 1.4 versicolor
8 6.8 2.8 4.8 1.4 versicolor
9 5.8 2.7 4.1 1 versicolor
10 6.4 3.2 4.5 1.5 versicolor
# ... with 17 more rows
Я полагаю, вы можете добавить weight_by = Species
в качестве аргумента, я просто не уверен, для какой цели это служит (это часть вашего вопроса, которую мне было трудно понять).
Да, спасибо за помощь. Я использовал map_df! Кстати какая разница в map2_df и map_df?
На самом деле, weight_by = Sepal.Length
отлично работает для меня. Веса по видам действительно бессмысленны. В моем фрейме данных я должен выполнять выборку по вероятности, пропорциональной размеру, без замены, где фактические веса хранятся в некотором столбце количества. Чтобы воспроизвести это на iris
, я попросил вес только для первого числового столбца.
map2()
- это когда вы хотите перебрать 2 набора элементов, чтобы войти в аргументы функции, а не только 1. например. map2(0:5, 1:6, function(x, y) rnorm(5, mean = x, sd = y))
сделаю rnorm(5, 0, 1)
, затем rnorm(5, 1, 2)
и т.д. до rnorm(5, 5, 6)
.
В моем предыдущем комментарии я хотел сказать weight_by = Sepal.Length
вместо weight_by = Species
. В любом случае, я не думаю, что это имеет отношение к вашей конкретной проблеме.
Аналогичное решение с использованием purrr
.
Сначала мы указываем наши пропорции для каждого Species
.
props <- c(setosa=0.1, versicolor=0.2, virginica=0.5)
Затем мы перебираем каждую пару имя-значение в props
, используя imap
. Для каждой пары в props
мы фильтруем строки фрейма данных, чтобы они содержали только этот вид, а затем выбираем соответствующий процент, указанный с помощью slice_sample
.
imap_dfr(props,
~filter(iris, Species==.y) %>%
slice_sample(prop=.x))
Затем с помощью imap_dfr
три фрейма данных (по одному для каждого вида) объединяются в один фрейм данных.
Вот результат:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 4.8 3.1 1.6 0.2 setosa
2 5.0 3.5 1.3 0.3 setosa
3 5.1 3.8 1.6 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
5 4.9 3.1 1.5 0.2 setosa
6 6.7 3.1 4.7 1.5 versicolor
7 5.7 2.8 4.1 1.3 versicolor
8 6.1 3.0 4.6 1.4 versicolor
9 5.6 3.0 4.5 1.5 versicolor
10 6.6 2.9 4.6 1.3 versicolor
11 5.5 2.6 4.4 1.2 versicolor
12 6.7 3.0 5.0 1.7 versicolor
13 5.7 2.6 3.5 1.0 versicolor
14 5.9 3.2 4.8 1.8 versicolor
15 5.4 3.0 4.5 1.5 versicolor
16 5.8 2.8 5.1 2.4 virginica
17 6.7 3.3 5.7 2.1 virginica
18 7.4 2.8 6.1 1.9 virginica
19 6.4 2.8 5.6 2.1 virginica
20 6.7 3.1 5.6 2.4 virginica
21 6.1 3.0 4.9 1.8 virginica
22 6.0 2.2 5.0 1.5 virginica
23 6.3 2.7 4.9 1.8 virginica
24 6.3 2.8 5.1 1.5 virginica
25 7.2 3.2 6.0 1.8 virginica
26 7.7 2.6 6.9 2.3 virginica
27 5.8 2.7 5.1 1.9 virginica
28 4.9 2.5 4.5 1.7 virginica
29 6.7 3.0 5.2 2.3 virginica
30 7.7 3.8 6.7 2.2 virginica
31 6.9 3.1 5.4 2.1 virginica
32 5.8 2.7 5.1 1.9 virginica
33 6.8 3.0 5.5 2.1 virginica
34 6.3 2.5 5.0 1.9 virginica
35 6.9 3.1 5.1 2.3 virginica
36 6.3 3.3 6.0 2.5 virginica
37 7.6 3.0 6.6 2.1 virginica
38 6.5 3.0 5.5 1.8 virginica
39 7.7 2.8 6.7 2.0 virginica
40 6.5 3.2 5.1 2.0 virginica
Вы можете хранить информацию о пропорциях в самом фрейме данных и выбирать из него строки.
library(dplyr)
iris %>%
distinct(Species) %>%
mutate(prop = c(0.1, 0.2, 0.25)) %>%
inner_join(iris, by = 'Species') %>%
group_by(Species) %>%
sample_n(first(prop)*n()) -> result
result %>% count(Species)
# Species n
# <fct> <int>
#1 setosa 5
#2 versicolor 10
#3 virginica 12
Я ожидал, что slice_sample(prop = first(prop))
сработает, но это не так, поэтому я использовал sample_n
.
Очень хороший подход, как всегда у Ронака. Спасибо. Просто чтобы знать, могу ли я установить семя в синтаксисе канала или мне нужно установить его в самом начале?
Установка его в самом начале должна дать вам те же образцы.
Да, как-то так, Могу ли я использовать weight_by в этом?