R语言 将多个列中的第一个字符子字符串连接到一个新列中,而不显式列出每个列名

nlejzf6q  于 2023-05-11  发布在  其他
关注(0)|答案(2)|浏览(81)

问题陈述

我有一个数据集,其中有100个诊断字段,存储为字符。它们被命名为DiagnosisCode1DiagnosisCode100。在大多数情况下,第一诊断字段是完整的,但并不总是如此。更高的诊断字段几乎普遍为空,如NA。我需要剥离每个字段的第一个字符,并将它们连接到一个名为OnsetFlags的列中。由于我将引用的列的数量很大,我不希望显式引用所有100个字段,而是使用dplyr助手(如starts_with())或使用范围(如DiagnosisCode1:DiagnosisCode100)来引用它。

示例数据

出于简明演示的目的,以下数据集使用5个诊断列:

example = structure(list(id = c("1", "2", "3", "4", 
"5", "6", "7"), DiagnosisCode1 = c("2G56.2", 
"2M48.06", "2G56.2", "2G56.0", "2S83.53", "2M23.20", "2S83.53"
), DiagnosisCode2 = c("2G56.0", "2G55.3", "2G56.0", "2G56.2", 
"2Y92.82", "2Z86.43", "2S83.2"), DiagnosisCode3 = c("2Z86.43", 
"2Z86.43", "2Z86.43", "1J98.1", "2V93.8", NA, "2W19"), DiagnosisCode4 = c(NA, 
"2U82.3", NA, "2U80.2", "2U73.8", NA, "2Y92.39"), DiagnosisCode5 = c(NA, 
"2U83.3", NA, NA, NA, NA, "2U56.39")), row.names = c(NA, -7L), class = "data.frame")

生产:

id DiagnosisCode1 DiagnosisCode2 DiagnosisCode3 DiagnosisCode4 DiagnosisCode5
1  1         2G56.2         2G56.0        2Z86.43           <NA>           <NA>
2  2        2M48.06         2G55.3        2Z86.43         2U82.3         2U83.3
3  3         2G56.2         2G56.0        2Z86.43           <NA>           <NA>
4  4         2G56.0         2G56.2         1J98.1         2U80.2           <NA>
5  5        2S83.53        2Y92.82         2V93.8         2U73.8           <NA>
6  6        2M23.20        2Z86.43           <NA>           <NA>           <NA>
7  7        2S83.53         2S83.2           2W19        2Y92.39        2U56.39

必填结果

id DiagnosisCode1 DiagnosisCode2 DiagnosisCode3 DiagnosisCode4 DiagnosisCode5 OnsetFlags
1  1          G56.2          G56.0         Z86.43           <NA>           <NA>        222
2  2         M48.06          G55.3         Z86.43          U82.3          U83.3      22222
3  3          G56.2          G56.0         Z86.43           <NA>           <NA>        222
4  4          G56.0          G56.2          J98.1          U80.2           <NA>       2212
5  5         S83.53         Y92.82          V93.8          U73.8           <NA>        222
6  6         M23.20         Z86.43           <NA>           <NA>           <NA>         22
7  7         S83.53          S83.2            W19         Y92.39         U56.39      22222

尝试次数

到目前为止,我已经用dplyracross()尝试了我常用的技巧:

# create onset flag array
  example = example %>% 
    mutate(OnsetFlags = across(starts_with("DiagnosisCode"), ~ as.character(substr(., 1, 1))
      ))

但是,这会创建一个tibble列,该tibble列本身包含多个OnsetFlags列,其数量等于DiagnosisCode列的数量。我很难将这些从tibble中提取出来并连接到dataframe列中,老实说,感觉它为我认为应该是一个简单的过程增加了很多开销。
我在SO上找到的最接近的其他例子是:
How can I concatenate two columns' data whilst only taking the first character of each entry to create an acronym in the new column?
...但我似乎不能unite的tibble列。
有没有更简单的方法来做到这一点,因为我觉得我没有走在正确的道路上?

z0qdvdin

z0qdvdin1#

如果这绝对必须在宽格式中完成,我会避免apply(它在每一行上循环,并且会在大型数据集上陷入困境),并以标准的向量化R方式嵌套处理substr/unite处理。这样的东西应该会起作用,尽管它可能会被改进。

example %>% 
    mutate(onset = example %>% 
                       select(starts_with("DiagnosisCode")) %>%
                       map_df(substr,1,1) %>%
                       unite("onset", na.rm=TRUE, sep="")
                       %>% pull(onset)
    )

然而,“整洁”方法将不适用于广泛的“不整洁”数据。相反,pivot_longer将其转换为一个长的、“整洁”的诊断数据集。
可以在适当的测量水平上加入来自长诊断数据集的任何汇总信息。这允许以非常简单的方式处理/分析分组的诊断和发作标志,而不会陷入变量前缀选择、应用/跨逻辑或由于每个事件的诊断数量不平衡而需要处理NA值(在旋转时注意values_drop_NA=TRUE)。

diagnosis <- example %>%
    pivot_longer(-id,
                 names_pattern=".+(\\d+)",
                 names_to="seq",
                 values_to="code",
                 values_drop_na=TRUE) %>%
    mutate(onset = as.integer(substr(code, 1, 1)),
           code  = substr(code, 2, nchar(code)))

diagnosis
## A tibble: 26 × 4
#   id    seq   code   onset
#   <chr> <chr> <chr>  <int>
# 1 1     1     G56.2      2
# 2 1     2     G56.0      2
# 3 1     3     Z86.43     2
# 4 2     1     M48.06     2
# 5 2     2     G55.3      2
# 6 2     3     Z86.43     2
# 7 2     4     U82.3      2
# 8 2     5     U83.3      2
# 9 3     1     G56.2      2
#10 3     2     G56.0      2
## … with 16 more rows

您当前的分析任务变得简单多了:

diagnosis %>%
    group_by(id) %>%
    summarise(onset = paste(onset,collapse=""))

## A tibble: 7 × 2
#  id    onset
#  <chr> <chr>
#1 1     222
#2 2     22222
#3 3     222
#4 4     2212
#5 5     2222
#6 6     22
#7 7     22222

尽管我认为组合 n 个起始值违反了组织数据的大多数良好实践,其中每个单元格应该只包含一个值,这使得未来的分析更加困难,因为您必须然后strsplit这些值才能理解它们。最好把它留在长格式中,并按原样分析它们。
下面是另一个关于如何处理长格式中其他更复杂分析的示例:

diagnosis %>%
    group_by(id) %>%
    summarise(onset1 = any(onset == 1),
              G5and2 = any(substr(code,1,2) == 'G5' & onset == 2))

## A tibble: 7 × 3
#  id    onset1 G5and2
#  <chr> <lgl>  <lgl>
#1 1     FALSE  TRUE
#2 2     FALSE  TRUE
#3 3     FALSE  TRUE
#4 4     TRUE   TRUE
#5 5     FALSE  FALSE
#6 6     FALSE  FALSE
#7 7     FALSE  FALSE
eanckbw9

eanckbw92#

您可以使用substring()substr()apply()

example |> 
  mutate(
    across(starts_with("Diagnosis"), ~substring(.x,2)),
    onsetFlag = apply(select(example, starts_with("Diagnosis")), 1, FUN = \(x) na.omit(substr(x, 1,1)) |> paste(collapse = "")))

输出

id DiagnosisCode1 DiagnosisCode2 DiagnosisCode3 DiagnosisCode4 DiagnosisCode5 onsetFlag
1  1          G56.2          G56.0         Z86.43           <NA>           <NA>       222
2  2         M48.06          G55.3         Z86.43          U82.3          U83.3     22222
3  3          G56.2          G56.0         Z86.43           <NA>           <NA>       222
4  4          G56.0          G56.2          J98.1          U80.2           <NA>      2212
5  5         S83.53         Y92.82          V93.8          U73.8           <NA>      2222
6  6         M23.20         Z86.43           <NA>           <NA>           <NA>        22
7  7         S83.53          S83.2            W19         Y92.39         U56.39     22222

相关问题