从值行中提取虚拟变量

问题描述 投票:0回答:3

我有一组相当大的分隔数据,列出了与这些合成数据类似的行中的个人特征:

id; ICD_Codes
1; F10.10; F11.21; F31.81
2; G89.29; M54.5; F31.4; F11.21; F17.200; F43.10; Z72.0
3; F14.10; F17.200; F31.81; F31.32; F10.21

(是的,每行的“列”数不同)

我想从中提取一系列虚拟代码,每个

ICD_Codes
值一个,并用给定的个人是否具有该值来填充这些虚拟变量,即:

id F10.10 F10.21 F11.21 F14.10 F17.200 F31.32 F31.4 F31.81 F43.10 G89.29 M54.5 Z72.0
1 1 0 1 0 0 0 0 1 0 0 0 0
2 0 0 1 0 1 0 1 0 1 1 1 1
3 0 1 0 1 1 1 0 1 0 0 0 0

或者,作为 R 数据框:

df <- data.frame(id = c(1, 2, 3),
                 F10.10 = c(1, 0, 0),
                 F10.21 = c(0, 0, 1),
                 F11.21 = c(1, 1, 0),
                 F14.10 = c(0, 0, 1),
                 F17.200 = c(0, 1, 1),
                 F31.32 = c(0, 0, 1),
                 F31.4 = c(0, 1, 0),
                 F31.81 = c(1, 0, 1),
                 F43.10 = c(0, 1, 0),
                 G89.29 = c(0, 1, 0),
                 M54.5 = c(0, 1, 0),
                 Z72.0 = c(0, 1, 0)
                 )

我想不出简单的方法来做到这一点(任何地方,包括在 R 中),但肯定有办法!

如果有任何帮助,我将不胜感激。

r dataframe dummy-variable
3个回答
1
投票

假设您还没有将数据导入 R,我们可以使用

read.table
将数据作为单列读取(选择一个您确定不会出现在数据中的随机
sep
符号)。

然后将

id
ICD_Codes
分成两列,并使用
fastDummies::dummy_cols()
创建虚拟变量。最后
rename
删除列前缀以适应您想要的输出。

library(dplyr)
library(tidyr)
library(fastDummies)

df <- read.table(text = "id; ICD_Codes
1; F10.10; F11.21; F31.81
2; G89.29; M54.5; F31.4; F11.21; F17.200; F43.10; Z72.0
3; F14.10; F17.200; F31.81; F31.32; F10.21", sep = "@", header = T)

df %>% 
  separate_wider_delim("id..ICD_Codes", names = c("id", "ICD_Codes"), delim = "; ", too_many = "merge") %>% 
  dummy_cols("ICD_Codes", remove_selected_columns = T, split = ";") %>% 
  rename_with(~sub("ICD_Codes_", "", .x))

# A tibble: 3 × 13
  id    F10.10 F11.21 F31.81 F14.10 F17.200 F31.32 F10.21 G89.29 M54.5 F31.4 F43.10 Z72.0
  <chr>  <int>  <int>  <int>  <int>   <int>  <int>  <int>  <int> <int> <int>  <int> <int>
1 1          1      1      1      0       0      0      0      0     0     0      0     0
2 2          0      1      0      0       1      0      0      1     1     1      1     1
3 3          0      0      1      1       1      1      1      0     0     0      0     0

1
投票

无需使用额外的包,您可以使用

readLines
strsplit
。然后使用
grepl
交叉
outer

read <- readLines(textConnection('id; ICD_Codes
1; F10.10; F11.21; F31.81
2; G89.29; M54.5; F31.4; F11.21; F17.200; F43.10; Z72.0
3; F14.10; F17.200; F31.81; F31.32; F10.21'))

read <- lapply(read, \(x) el(strsplit(x, split=';\\s*')))
icd <- sort(unique(unlist(lapply(read[-1], \(x) x[-1]))))
o <- t(outer(icd, read[-1], Vectorize(\(sprintf('^%s$', x), y) any(grepl(x, y)))))
data.frame(id=sapply(read[-1], `[`, 1), `colnames<-`(+o, icd))
#   id F10.10 F10.21 F11.21 F14.10 F17.200 F31.32 F31.4 F31.81 F43.10 G89.29 M54.5 Z72.0
# 1  1      1      0      1      0       0      0     0      1      0      0     0     0
# 2  2      0      0      1      0       1      0     1      0      1      1     1     1
# 3  3      0      1      0      1       1      1     0      1      0      0     0     0

注意: 对于您的真实数据,您可能需要使用

readLines(<path>)
.

证据表明它比 tidyverse 解决方案快得多:

# Unit: microseconds
#     expr       min         lq      mean    median        uq       max neval cld
#   jay.sf   965.285   994.9295  1264.239  1089.907  1124.969  16915.81   100  a 
# benson23 17309.835 17533.8145 20036.727 17822.965 18763.764 159236.18   100   b

0
投票

只需使用

mtabulate

library(qdapTools)
cbind(id = sub(";.*", "", df[[1]]),
   mtabulate(strsplit(sub("^\\d+;\\s+", "", df[[1]]), ";\\s*")))

-输出

   id F10.10 F10.21 F11.21 F14.10 F17.200 F31.32 F31.4 F31.81 F43.10 G89.29 M54.5 Z72.0
1  1      1      0      1      0       0      0     0      1      0      0     0     0
2  2      0      0      1      0       1      0     1      0      1      1     1     1
3  3      0      1      0      1       1      1     0      1      0      0     0     0
© www.soinside.com 2019 - 2024. All rights reserved.