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

Я хочу сделать случайную выборку из своего набора данных, используя разные пропорции для каждого значения факторной переменной, а также используя веса, хранящиеся в каком-то другом столбце. 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

Пожалуйста помоги

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
269
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Если я правильно тебя понял:

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 в этом?

AnilGoyal 13.12.2020 06:29

Я полагаю, вы можете добавить weight_by = Species в качестве аргумента, я просто не уверен, для какой цели это служит (это часть вашего вопроса, которую мне было трудно понять).

Phil 13.12.2020 06:32

Да, спасибо за помощь. Я использовал map_df! Кстати какая разница в map2_df и map_df?

AnilGoyal 13.12.2020 06:32

На самом деле, weight_by = Sepal.Length отлично работает для меня. Веса по видам действительно бессмысленны. В моем фрейме данных я должен выполнять выборку по вероятности, пропорциональной размеру, без замены, где фактические веса хранятся в некотором столбце количества. Чтобы воспроизвести это на iris, я попросил вес только для первого числового столбца.

AnilGoyal 13.12.2020 06:36
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).
Phil 13.12.2020 06:37

В моем предыдущем комментарии я хотел сказать weight_by = Sepal.Length вместо weight_by = Species. В любом случае, я не думаю, что это имеет отношение к вашей конкретной проблеме.

Phil 13.12.2020 06:38

Аналогичное решение с использованием 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.

Очень хороший подход, как всегда у Ронака. Спасибо. Просто чтобы знать, могу ли я установить семя в синтаксисе канала или мне нужно установить его в самом начале?

AnilGoyal 13.12.2020 11:00

Установка его в самом начале должна дать вам те же образцы.

Ronak Shah 13.12.2020 11:02

Другие вопросы по теме