Элегантный способ делать вложенные операторы if else для нескольких групп

Вот что я пытаюсь сделать:

Создайте новый столбец, который присваивает выборочный ранг нескольким подмножествам строк в зависимости от количества строк в каждом подмножестве. Группирующей переменной является столбец "страта".

Обычно я назначаю ранг случайным образом, используя вложенные операторы ifelse, как показано ниже. Иногда этого достаточно, но в последнее время я сталкиваюсь со все большим количеством группировок. 40 вложенных операторов ifelse могут показаться немного чрезмерными.

Есть ли более элегантный / быстрый / минимальный способ сделать это с помощью dplyr или data.table, возможно, в сочетании с apply, lapply, sapply и т. д.?

Я пробовал использовать операторы data.table, но не знаю, как вставить функцию-образец с помощью nrow.

Воспроизводимые данные:

dta <- data.frame(
     uniqueID = c(950513, 951634, 951640, 951641,951646, 952732, 952895, 952909, 952910, 952911, 952912,952923, 952924, 952925, 952926, 952927, 952928L, 952933, 
           952934, 952935),
     stratum = c("group9","group6","group15","group13","group9","group8","group9","group15","group15","group15","group15", "group13", "group13", 
          "group1", "group1", "group1", "group1", "group1", "group1", "group1")
)

Вот как я обычно присваиваю случайный ранг, используя оператор netsed ifelse:

dta<- dta[order(dta$stratum),]  
set.seed(7265)                                                                                                                 

dta$rank <- ifelse(dta$stratum== "group1",sample(1:nrow(dta[dta$stratum== "group1",])),
               ifelse(dta$stratum=="group6",sample(1:nrow(dta[dta$stratum== "group6",])),
                      ifelse(dta$stratum=="group8",sample(1:nrow(dta[dta$stratum== "group8",])),
                             ifelse(dta$stratum=="group9",sample(1:nrow(dta[dta$stratum== "group9",])),
                                    ifelse(dta$stratum=="group13",sample(1:nrow(dta[dta$stratum== "group13",])),
                                           ifelse(dta$stratum=="group15",sample(1:nrow(dta[dta$stratum== "group15",])),
                                                  0))))))

person st2coker    schedule 27.12.2017    source источник


Ответы (3)


Решение с использованием data.table:

library(data.table)
setDT(dta)[, rank := sample(1:.N), stratum]

 #     uniqueID stratum rank
 #  1:   952925  group1    4
 #  2:   952926  group1    2
 #  3:   952927  group1    1
 #  4:   952928  group1    6
 #  5:   952933  group1    7
 #  6:   952934  group1    3
 #  7:   952935  group1    5
 #  8:   951641 group13    2
 #  9:   952923 group13    1
 # 10:   952924 group13    3
 # ...

Объяснение:

  1. Преобразовать объект в data.table (setDT())
  2. Выборочный рейтинг для каждой группы (, stratum]) от 1 до .N (сколько строк в каждой группе)
person pogibas    schedule 27.12.2017

Используя dplyr, вы можете сделать

library(dplyr)
dta %>% 
    group_by(stratum) %>% 
    mutate(rank=sample.int(n()))

group_by позволяет вам работать с подмножеством строк за раз, и мы используем встроенную функцию n() из dplyr, чтобы получить количество строк в каждой группе. Я решил использовать более эффективный sample.int, а не sample, но он в основном делает то же самое.

В общем, вложенные операторы if-else лучше обрабатывать с помощью case_when() в dplyr, но то, что вы делали в этом случае, лучше обрабатывать с помощью group_by()

person MrFlick    schedule 27.12.2017
comment
Благодарю. я могу принять только один ответ, но этот тоже работает хорошо! - person st2coker; 27.12.2017

Рассмотрим by в базе R, предназначенную для разделения фреймов данных на фактор (ы):

dta$rank <- unlist(by(dta, dta$stratum, FUN=function(df) sample(1:nrow(df))))

#    uniqueID stratum rank
# 14   952925  group1    6
# 15   952926  group1    2
# 16   952927  group1    1
# 17   952928  group1    3
# 18   952933  group1    5
# 19   952934  group1    7
# 20   952935  group1    4
# 4    951641 group13    2
# 12   952923 group13    1
# 13   952924 group13    3
# 3    951640 group15    1
# 8    952909 group15    3
# 9    952910 group15    5
# 10   952911 group15    2
# 11   952912 group15    4
# 2    951634  group6    1
# 6    952732  group8    1
# 1    950513  group9    2
# 5    951646  group9    1
# 7    952895  group9    3
person Parfait    schedule 27.12.2017
comment
Я почти публиковал это хахах transform(dta,rank=unname(unlist(by(dta,stratum,function(x)sample(nrow(x)))))) - person Onyambu; 27.12.2017
comment
Великие умы думают одинаково, как говорится! И приятно видеть здесь поддержку base R! Ваше здоровье - person Parfait; 27.12.2017