如果类别以 R 中的特定字母开头,如何在 R 中的多列中进行过滤?
How to filter in multiple columns in R if the category starts with specific letter in R?
我有一个庞大的数据集,其中包含超过 200 万个 obs 和 100 列。有 9 列包含 ICD-10 疾病代码,每列都以不同的字母开头。
例如:
icd1 <- c("O230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "R433")
icd2 <- c("O230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "Z433")
icd3 <- c("X230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "Z433")
data <- as.data.frame(rbind(icd1, icd2, icd3))
我需要做的是创建一个名为“ICD_Z”的新列来检查这 9 个 ICD-10 列代码中的每一个,看看它们是否以字母 Z 开头,如果是在这种情况下,我创建的列将接收 1,否则接收 0。但如果所有这 9 列都没有以字母 O 开头的 ICD-10 代码,它只能接收 1。
所以我的输出看起来像这样:
我该怎么做?
结合使用 rowwise()
和 c_across()
非常简单:
library(dplyr)
icd1 <- c("O230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "R433")
icd2 <- c("O230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "Z433")
icd3 <- c("X230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "Z433")
data <- as.data.frame(rbind(icd1, icd2, icd3))
data %>%
rowwise() %>%
mutate(has_z = any(startsWith(c_across(V1:V9), "Z")),
has_o = any(startsWith(c_across(V1:V9), "O")),
icdz = as.numeric(has_z & !has_o)
) %>%
select(-has_z, -has_o)
#> # A tibble: 3 × 10
#> # Rowwise:
#> V1 V2 V3 V4 V5 V6 V7 V8 V9 icdz
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
#> 1 O230 B540 D990 Y555 E980 J777 P090 Q090 R433 0
#> 2 O230 B540 D990 Y555 E980 J777 P090 Q090 Z433 0
#> 3 X230 B540 D990 Y555 E980 J777 P090 Q090 Z433 1
由 reprex package (v2.0.1)
于 2022-05-25 创建
更新:更快的方法:
icd_cols = paste0("V",1:9)
f <- function(v) !any(v=="O") & any(v=="Z")
setDT(data)
set(data, j="icdz", value= apply(data[,..icd_cols],1,\(i) f(substr(i,1,1))))
原解
对于您的大型数据集,您可能会使用这种使用 data.table 的方法来加快速度。在 3 行的小示例中,我非正式地发现这大约快 5 倍。
- 确定9个ICD列的列表;我在这里使用了一个简单的结构来得到 V1:V9,但你可以使用
icd_cols = colnames(data)[c(20,21,37:45)]
- 创建一个计算首字母向量的小函数
- 将原始帧设置为data.table
- 通过id熔化并应用函数,并将结果赋值给原始帧
icd_cols = paste0("V",1:9)
f <- function(v) !any(v=="O") & any(v=="Z")
setDT(data)
data[, icdz:=(melt(data[,id:=.I],"id",icd_cols)[,f(substr(value,1,1)), by=id]$V1)][id:=NULL]
输出:
V1 V2 V3 V4 V5 V6 V7 V8 V9 icdz
1: O230 B540 D990 Y555 E980 J777 P090 Q090 R433 FALSE
2: O230 B540 D990 Y555 E980 J777 P090 Q090 Z433 FALSE
3: X230 B540 D990 Y555 E980 J777 P090 Q090 Z433 TRUE
您可以使用 if_any
和 if_all
:
data %>%
mutate(ICD_Z = if_any(V1:V9, ~grepl('^Z', .)) *
if_all(V1:V9, ~!grepl('^O', .)))
V1 V2 V3 V4 V5 V6 V7 V8 V9 ICD_Z
icd1 O230 B540 D990 Y555 E980 J777 P090 Q090 R433 0
icd2 O230 B540 D990 Y555 E980 J777 P090 Q090 Z433 0
icd3 X230 B540 D990 Y555 E980 J777 P090 Q090 Z433 1
编辑:
您可以使用变量来存储相关列的位置:
nms <- c(1,2,3,5,7,8)
data %>%
mutate(ICD_Z = if_any(all_of(nms), ~grepl('^Z', .)) *
if_all(all_of(nms), ~!grepl('^O', .)))
我有一个庞大的数据集,其中包含超过 200 万个 obs 和 100 列。有 9 列包含 ICD-10 疾病代码,每列都以不同的字母开头。
例如:
icd1 <- c("O230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "R433")
icd2 <- c("O230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "Z433")
icd3 <- c("X230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "Z433")
data <- as.data.frame(rbind(icd1, icd2, icd3))
我需要做的是创建一个名为“ICD_Z”的新列来检查这 9 个 ICD-10 列代码中的每一个,看看它们是否以字母 Z 开头,如果是在这种情况下,我创建的列将接收 1,否则接收 0。但如果所有这 9 列都没有以字母 O 开头的 ICD-10 代码,它只能接收 1。
所以我的输出看起来像这样:
我该怎么做?
结合使用 rowwise()
和 c_across()
非常简单:
library(dplyr)
icd1 <- c("O230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "R433")
icd2 <- c("O230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "Z433")
icd3 <- c("X230", "B540", "D990", "Y555", "E980", "J777", "P090", "Q090", "Z433")
data <- as.data.frame(rbind(icd1, icd2, icd3))
data %>%
rowwise() %>%
mutate(has_z = any(startsWith(c_across(V1:V9), "Z")),
has_o = any(startsWith(c_across(V1:V9), "O")),
icdz = as.numeric(has_z & !has_o)
) %>%
select(-has_z, -has_o)
#> # A tibble: 3 × 10
#> # Rowwise:
#> V1 V2 V3 V4 V5 V6 V7 V8 V9 icdz
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
#> 1 O230 B540 D990 Y555 E980 J777 P090 Q090 R433 0
#> 2 O230 B540 D990 Y555 E980 J777 P090 Q090 Z433 0
#> 3 X230 B540 D990 Y555 E980 J777 P090 Q090 Z433 1
由 reprex package (v2.0.1)
于 2022-05-25 创建更新:更快的方法:
icd_cols = paste0("V",1:9)
f <- function(v) !any(v=="O") & any(v=="Z")
setDT(data)
set(data, j="icdz", value= apply(data[,..icd_cols],1,\(i) f(substr(i,1,1))))
原解
对于您的大型数据集,您可能会使用这种使用 data.table 的方法来加快速度。在 3 行的小示例中,我非正式地发现这大约快 5 倍。
- 确定9个ICD列的列表;我在这里使用了一个简单的结构来得到 V1:V9,但你可以使用
icd_cols = colnames(data)[c(20,21,37:45)]
- 创建一个计算首字母向量的小函数
- 将原始帧设置为data.table
- 通过id熔化并应用函数,并将结果赋值给原始帧
icd_cols = paste0("V",1:9)
f <- function(v) !any(v=="O") & any(v=="Z")
setDT(data)
data[, icdz:=(melt(data[,id:=.I],"id",icd_cols)[,f(substr(value,1,1)), by=id]$V1)][id:=NULL]
输出:
V1 V2 V3 V4 V5 V6 V7 V8 V9 icdz
1: O230 B540 D990 Y555 E980 J777 P090 Q090 R433 FALSE
2: O230 B540 D990 Y555 E980 J777 P090 Q090 Z433 FALSE
3: X230 B540 D990 Y555 E980 J777 P090 Q090 Z433 TRUE
您可以使用 if_any
和 if_all
:
data %>%
mutate(ICD_Z = if_any(V1:V9, ~grepl('^Z', .)) *
if_all(V1:V9, ~!grepl('^O', .)))
V1 V2 V3 V4 V5 V6 V7 V8 V9 ICD_Z
icd1 O230 B540 D990 Y555 E980 J777 P090 Q090 R433 0
icd2 O230 B540 D990 Y555 E980 J777 P090 Q090 Z433 0
icd3 X230 B540 D990 Y555 E980 J777 P090 Q090 Z433 1
编辑:
您可以使用变量来存储相关列的位置:
nms <- c(1,2,3,5,7,8)
data %>%
mutate(ICD_Z = if_any(all_of(nms), ~grepl('^Z', .)) *
if_all(all_of(nms), ~!grepl('^O', .)))