我有一个包含 150 列的数据集,其中列被命名为 Qa101 到 Qa150、Qb101 到 Qb150 和 Qc101 到 Qc150。计划是将名称的最后三个字符(例如 101)共享的列合并起来,并且每 3 个共享最后三个字符的列只有一列,例如 Qa101、Qb101 和 Qc101,应合并为 Q101。的列都是数值,可以肯定的是,这三列中只有一列共享最后三个字符保存值,另外两列为 NA,例如 Qa101 为数值,Qb101 和 Qc101 为 NA,等等在。 我希望找到一个 tidyverse 解决方案,但在这个阶段我会接受任何事情。
我已经使用 dplyr 函数尝试了不同的不成功方法,例如:
data.test <- data %>%
mutate(across(where(~str_match(., start=-3))),unite(remove= TRUE, na.rm=TRUE),.keep = "none")
但这显然是错误的。
一个
tidyverse
示例。 data
由 150 列组成,按照您的问题命名,只有“Qb”列不是 NA
。
library(tidyverse)
data <- data.frame(matrix(1:450, nrow = 3, ncol = 150))
data[, c(1:50, 101:150)] <- NA
names(data) <-
paste(rep(c("Qa", "Qb", "Qc"), each = length(101:150)), 101:150, sep = "")
的想法是使用
pivot_longer()
,然后连接相关列的值。最后,我们使用 pivot_wider()
将其转换回来。
data |>
mutate(id = row_number()) |>
pivot_longer(
cols = c(-id),
names_to = "colname",
values_to = c("value")
) |>
mutate(helper = str_c(str_sub(colname, 1, 1), str_sub(colname, -3, -1))) |>
filter(!is.na(value)) |>
select(-c(colname)) |>
distinct() |>
pivot_wider(names_from = helper, values_from = value) |>
select(-id)
# A tibble: 3 × 50
Q101 Q102 Q103 Q104 Q105 Q106 Q107 Q108 Q109 Q110 Q111 Q112 Q113 Q114 Q115
<int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
1 151 154 157 160 163 166 169 172 175 178 181 184 187 190 193
2 152 155 158 161 164 167 170 173 176 179 182 185 188 191 194
3 153 156 159 162 165 168 171 174 177 180 183 186 189 192 195
# ℹ 35 more variables: Q116 <int>, Q117 <int>, Q118 <int>, Q119 <int>, Q120 <int>,
# Q121 <int>, Q122 <int>, Q123 <int>, Q124 <int>, Q125 <int>, Q126 <int>, Q127 <int>,
# Q128 <int>, Q129 <int>, Q130 <int>, Q131 <int>, Q132 <int>, Q133 <int>, Q134 <int>,
# Q135 <int>, Q136 <int>, Q137 <int>, Q138 <int>, Q139 <int>, Q140 <int>, Q141 <int>,
# Q142 <int>, Q143 <int>, Q144 <int>, Q145 <int>, Q146 <int>, Q147 <int>, Q148 <int>,
# Q149 <int>, Q150 <int>
如上所述:
可以肯定的是,这三列中只有一列共享最后三个字符(例如
、Qa101
、Qb101
)持有值,另外两列是 NA。Qc101
我创建了一个最小的示例数据集:
set.seed(123)
df <- as.data.frame(
matrix(t(replicate(9, sample(c(sample(1:10, 1), NA, NA)))), 3, 9,
dimnames = list(NULL, paste0(rep(c("Qa", "Qb", "Qc"), each = 3), 101:103)))
)
# Qa101 Qa102 Qa103 Qb101 Qb102 Qb103 Qc101 Qc102 Qc103
# 1 NA NA NA 3 NA 8 NA 10 NA
# 2 NA NA NA 2 3 9 NA NA NA
# 3 NA 9 NA NA NA 1 4 NA NA
您可以
pivot_longer()
处理列组,然后 summarise()
按行 ID 保留唯一的非缺失值。
library(tidyverse)
df %>%
mutate(ID = row_number()) %>%
pivot_longer(matches("Q[abc]"),
names_to = c(NA, ".value"),
names_pattern = "(\\D+)(\\d+)") %>%
summarise(across(`101`:`103`, ~ .x[!is.na(.x)][1], .names = "Q{.col}"),
.by = ID)
# ID Q101 Q102 Q103
# <int> <int> <int> <int>
# 1 1 3 10 8
# 2 2 2 3 9
# 3 3 4 9 1