这是使用tidyverse 包的一次尝试。在将所有内容转换为字符(即grade[] <- lapply(grade, as.character))后,我们创建了一个自定义函数,该函数为每个StudentID 返回排序后的subject:grade。然后我们用unnest把它变长,用separate把它分成两列; Subject 和 Grade。最后我们spread 为每个主题获取一列。
library(tidyverse)
#This function could definetely be more elegant or even avoided
# but this is as far as my regex knowledge allows me to go
mysplit <- function(x){
y <- strsplit(x, ':\\s+|\\s+')[[1]]
z <- paste0(y[c(T, F)], ': ', y[c(F, T)])
return(z[order(sub(':.*', '', z))])
}
grade %>%
mutate(Grade = lapply(Grade, mysplit)) %>%
unnest() %>%
separate(Grade, into = c('Subject', 'Grade'), sep = ': ') %>%
spread(Subject, Grade)
这样拆分:
... Biology Chemitry English Geography History Literature Math Physics
... 1 6.00 6.00 <NA> <NA> <NA> 7.50 4.25 6.80
... 2 5.80 6.00 <NA> <NA> <NA> 6.00 5.75 <NA>
... 3 <NA> <NA> <NA> 8.00 4.50 7.75 2.25 <NA>
... 4 <NA> <NA> <NA> 7.25 7.50 7.75 3.25 <NA>
... 5 <NA> <NA> <NA> 7.75 4.50 8.25 1.75 <NA>
... 6 <NA> 6.60 6.78 <NA> <NA> 7.00 8.75 8.40
.
.
为了更好地理解这个函数,你应该把它分解。
说 x 如下:
x
#[1] "Math: 4.25 Literature: 7.50 Physics: 6.80 Chemitry: 6.00 Biology: 6.00"
将其每space或: space拆分,得到以下向量
y <- strsplit(x, ':\\s+|\\s+')[[1]]
y
#[1] "Math" "4.25" "Literature" "7.50" "Physics" "6.80" "Chemitry" "6.00" "Biology" "6.00"
将所有第一个元素(即科目,y[c(TRUE, FALSE)])粘贴在一起,然后将所有第二个元素(即成绩y[c(FALSE, TRUE)])用:分隔符粘贴在一起
z <- paste0(y[c(T, F)], ': ', y[c(F, T)])
z
#[1] "Math: 4.25" "Literature: 7.50" "Physics: 6.80" "Chemitry: 6.00" "Biology: 6.00"
最后它输出一个排序好的(基于单词sub(':.*', '', z))向量
z[order(sub(':.*', '', z))]
#[1] "Biology: 6.00" "Chemitry: 6.00" "Literature: 7.50" "Math: 4.25" "Physics: 6.80"
正如@rosscova 指出的那样,不需要对字符串进行排序,这大大简化了这一点(毕竟不需要函数),即
grade %>%
mutate(Grade = strsplit(Grade, '[0-9]\\s+')) %>%
unnest() %>%
separate(Grade, into = c('Subject', 'Grade'), sep = ': ') %>%
spread(Subject, Grade)