为多个组做嵌套 if else 语句的优雅方式
Elegant way to do nested if else statements for multiple groups
这是我正在尝试做的事情:
创建一个新列,根据每个子集中的行数将样本排名分配给多个行子集。分组变量是 'stratum' 列。
我通常使用嵌套的 ifelse 语句随机分配排名,如下所示。有时这就足够了,但最近,我一直在处理越来越多的分组。 40 个嵌套的 ifelse 语句看起来有点过分。
是否有更多 elegant/quicker/minimal 代码方法可以使用 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))))))
使用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
# ...
解释:
- 将对象转换为
data.table
(setDT()
)
- 从 1 到
.N
(每组有多少行)每组样本排名 (, stratum]
)
使用dplyr
,你可以做到
library(dplyr)
dta %>%
group_by(stratum) %>%
mutate(rank=sample.int(n()))
group_by
允许您一次对行的子集进行操作,我们使用 dplyr
中的内置 n()
函数来获取每组中的行数.我选择使用更高效的 sample.int
而不是 sample
但它基本上做同样的事情。
一般来说,嵌套的 if-else 语句最好用 dplyr
中的 case_when()
处理,但是你在这种情况下所做的事情最好用 group_by()
[=20 处理=]
考虑基础 R 的 by
,旨在按因素拆分数据帧:
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
这是我正在尝试做的事情:
创建一个新列,根据每个子集中的行数将样本排名分配给多个行子集。分组变量是 'stratum' 列。
我通常使用嵌套的 ifelse 语句随机分配排名,如下所示。有时这就足够了,但最近,我一直在处理越来越多的分组。 40 个嵌套的 ifelse 语句看起来有点过分。
是否有更多 elegant/quicker/minimal 代码方法可以使用 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))))))
使用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
# ...
解释:
- 将对象转换为
data.table
(setDT()
) - 从 1 到
.N
(每组有多少行)每组样本排名 (, stratum]
)
使用dplyr
,你可以做到
library(dplyr)
dta %>%
group_by(stratum) %>%
mutate(rank=sample.int(n()))
group_by
允许您一次对行的子集进行操作,我们使用 dplyr
中的内置 n()
函数来获取每组中的行数.我选择使用更高效的 sample.int
而不是 sample
但它基本上做同样的事情。
一般来说,嵌套的 if-else 语句最好用 dplyr
中的 case_when()
处理,但是你在这种情况下所做的事情最好用 group_by()
[=20 处理=]
考虑基础 R 的 by
,旨在按因素拆分数据帧:
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