Как в R соответствовать нескольким условиям? - PullRequest
1 голос
/ 17 июня 2020

Мне нужно разделить данные в DF1 на группы в зависимости от их класса. В некоторых случаях все в классе будут в одной группе. Класс необходимо разделить на группы случайным образом, а не равными долями. В DF2 у меня есть данные, которые показывают, как данные должны быть разделены. DF2 импортирован мной из excel. Этот файл хранится мной, и при необходимости вы можете вносить изменения в структуру данных. Это файл, который я буду использовать для разделения классов на группы. Столбец «Поделиться» сообщает мне, сколько учеников класса должно быть разделено на эту группу. Например, 50% строк в DF1 с классом 1 должны быть разделены на яблоки, 25% на молотки и 25% на автомобили. NB! Он должен быть случайным, не может быть, что первые 50% строк - это яблоки, следующие 25% - молотки и т. Д. c.

Мое решение состоит в том, чтобы дать каждой строке в DF1 случайное число, которое я сохраняю каждый раз, когда делаю это, чтобы я мог go вернуться и использовать семя, которое я получил раньше. NB! Для меня важно, чтобы я мог go вернуться к предыдущему случайному результату, если я или мой коллега по ошибке запустили код и создали новое случайное начальное число. У меня есть эта часть случайного числа.

DF1 (base data)          
ID   Class   Random     
1      1      0,65
2      1      0,23
3      2      0,45
4      1      0,11
5      2      0,89
6      3      0,12
7      1      0,9 

Мое решение - создать столбец share_2, в котором я делю 0-1 на пробелы в зависимости от столбца share. В excel logi c я хотел бы сделать следующее:

IF Class = 1 then
IF Random < 0,5; Apples; if not then
IF Random < 0,75; Hammer if not then
IF Random <1; Car
DF2  (Classification file made by me)
Class   Group          Share      Share_2
1       Apples        50%*        0,5
1       Hammer        25%         0,75
1       Car           25%         1
2       Building      100%**      1
3       Computer      50%         0,5
3       Hammer        50%         1

*This means that 50% of class 1 need to be "Apples". Shares in a class give 100% in total. 

Мне нужно

DF3
ID   Class   Random      Group    
1      1      0,65      Hammer
2      1      0,23      Apples
3      2      0,45      Building
4      1      0,11      Apples
5      2      0,89      Building
6      3      0,12      Computer
7      1      0,9       Car

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

Ответы [ 2 ]

1 голос
/ 17 июня 2020

Один из способов go об этом, который не использует уже сгенерированные вами случайные числа, но в остальном довольно короткий, состоит в том, чтобы использовать функцию random() для выполнения случайного назначения непосредственно для you:

DF1 <- data.frame(
  ID = 1:7,
  Class = c(1, 1, 2, 1, 2, 3, 1),
  Random = c(0.65, 0.23, 0.45, 0.11, 0.89, 0.12, 0.9)
)

DF1 <- DF1[order(DF1$Class), ]  #EDIT: need this for the code to behave properly!

DF2 <- data.frame(
  Class = c(1, 1, 1, 2, 3, 3),
  Group = c("Apples", "Hammer", "Car", "Building", "Computer", "Hammer"),
  Share = c(0.5, 0.25, 0.25, 1, 0.5, 0.5),
  Share_2 = c(0.5, 0.75, 1, 1, 0.5, 1)
)

set.seed(12345)  # this is for reproducibility; you can choose any number here

DF3 <- DF1

DF3$Group <- unlist(sapply(unique(DF1$Class), function(x) {
  with(DF2[DF2$Class == x, ], 
       sample(Group, size = sum(DF3$Class == x), 
              prob = Share, replace = TRUE))
}))

Работа извне внутри: параметр sapply играет, по сути, роль for l oop. Он начинается с просмотра всех уникальных записей в DF1$Class. Для каждого из них (называемого x) он вырезает кусок DF2, соответствующий части, в которой Class равно x, а затем фокусируется только на этом фрагменте DF2 - это что здесь делает функция with().

Основная идея - использовать sample(). Мы рисуем объекты для выборки из столбца Group в DF2, рисуем соответствующее количество выборок (отмеченных параметром size), устанавливаем вероятности в соответствии со столбцом Share из DF2 и рисуем с заменой. Все это имеет смысл, потому что мы находимся внутри функции with(); мы уже ограничили наше внимание не только DF2, но только фрагментом DF2, соответствующим Class == x.

Функция unlist() используется, потому что вывод функции sapply() список в данном случае, и мы хотим, чтобы он был просто вектором; затем мы просто приклеиваем этот вектор непосредственно к кадру данных DF3, который в противном случае является идентичной копией DF1.

EDIT: Я добавил сортировку строк DF1, что необходимо для этого решения.

0 голосов
/ 17 июня 2020

На самом деле мне не нравится это решение, так как я передаю две filter -функции и не знаю, как это сделать в одном операторе.

Используя dplyr и данные @Aaron Montgomery:

merge(DF1, DF2, by="Class") %>%
  group_by(Class, ID) %>%
  filter(Random <= Share_2) %>%
  filter(Share_2 == min(Share_2)) %>%
  select(-c(Share, Share_2)) %>%
  arrange(ID)

дает

# A tibble: 7 x 4
# Groups:   Class, ID [7]
  Class    ID Random Group   
  <dbl> <int>  <dbl> <chr>   
1     1     1   0.65 Hammer  
2     1     2   0.23 Apples  
3     2     3   0.45 Building
4     1     4   0.11 Apples  
5     2     5   0.89 Building
6     3     6   0.12 Computer
7     1     7   0.9  Car  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...