R 中的复杂数据转换优化
Complex data transformation optimization in R
我写了一些非常非常难看的代码来执行数据转换。我知道它可能可以被矢量化并显着加速,但我不确定如何。
我的数据是这样的:
scores<-as.data.frame(cbind(c(1,2,3,3,1,2,3,1,2,1,2,3),c(5,5,5,5,6,6,6,7,7,8,8,8),
c(0,1,1,1,1,0,1,.5,"fickle",1,2.2,1),c(1,1,1,2,1,1,1,1,1,1,1,1)))
names(dat)<-c("name","question_id","correct","attempt")
ids<-c(5,7,8)
我想要的是创建一个 studentXquestion 矩阵,显示他们在包含在 ids 向量中的每个问题上的最终尝试分数。如果学生没有完成该问题,它也会给出 NA,如果 "correct" 列中出现 0 或 1 以外的某些值,它也会给出 99,因为有些数据有点难看。
下面是我目前的代码。
students<-unique(scores$name)
finaldat<-data.frame(matrix(ncol=length(ids),nrow=length(unique(students))))
for(i in 1:length(students)){
for(j in 1:length(ids)){
attempts<-which(scores$question_id==ids[j] &
scores$name==students[i])
if(length(attempts)==0){finaldat[i,j]<-NA}
else{
last.score<-as.numeric(scores$correct[attempts[which(attempts==length(attempts))]])
finaldat[i,j]<-99
if(length(last.score)==0){finaldat[i,j]<-NA}
else{if(last.score==0 | last.score==1){
finaldat[i,j]<-last.score
}
}
}
}
}
finaldat
除了 运行 真的很慢,它不起作用,因为我无法绕过 last.score 行。我确定有一个整洁的 verse 解决方案,但我很难过。任何提示将不胜感激。
所以输出数据将是:
cbind(c(0,1,1),c(99,99,NA),c(1,99,1))
我们可以看到第6题已经被排除,所有非二进制都被转换为99,缺失值是NA,只保留最后的尝试。
这是使用 dplyr
和 tidyr
的版本。
library(dplyr)
library(tidyr)
scores <- data.frame(name = c(1, 2, 3, 3, 1, 2, 3, 1, 2, 1, 2, 3),
question_id = c(5, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8),
correct = c(0, 1, 1, 1, 1, 0, 1, .5 , "fickle", 1, 2.2, 1),
attempt = c(1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1),
stringsAsFactors = FALSE)
result <- scores %>%
group_by(name, question_id) %>%
filter(attempt == max(as.numeric(as.character(attempt)))) %>%
mutate(correct = if(correct != "1" && correct != "0") "99" else correct) %>%
select(name, question_id, correct) %>%
ungroup() %>%
pivot_wider(names_from = question_id, values_from = correct)
result
#> # A tibble: 3 x 5
#> name `5` `6` `7` `8`
#> <dbl> <chr> <chr> <chr> <chr>
#> 1 1 0 1 99 1
#> 2 2 1 0 99 99
#> 3 3 1 1 <NA> 1
只是为了添加另一个解决方案,我已经在努力
library(data.table)
library(dplyr)
library(forcats)
dt.scores <- data.table(scores)
dt.scores[, correct := as.integer(as.character(fct_other(correct, keep = c("0", "1"), other_level = "99"))) ]
dt.scores[, attempt := as.integer(as.character(attempt)) ]
dt.scores[,.(name, question_id, correct)] %>% pivot_wider(data = . , names_from = question_id, values_from = correct, values_fn = list(correct = max))
我写了一些非常非常难看的代码来执行数据转换。我知道它可能可以被矢量化并显着加速,但我不确定如何。
我的数据是这样的:
scores<-as.data.frame(cbind(c(1,2,3,3,1,2,3,1,2,1,2,3),c(5,5,5,5,6,6,6,7,7,8,8,8),
c(0,1,1,1,1,0,1,.5,"fickle",1,2.2,1),c(1,1,1,2,1,1,1,1,1,1,1,1)))
names(dat)<-c("name","question_id","correct","attempt")
ids<-c(5,7,8)
我想要的是创建一个 studentXquestion 矩阵,显示他们在包含在 ids 向量中的每个问题上的最终尝试分数。如果学生没有完成该问题,它也会给出 NA,如果 "correct" 列中出现 0 或 1 以外的某些值,它也会给出 99,因为有些数据有点难看。
下面是我目前的代码。
students<-unique(scores$name)
finaldat<-data.frame(matrix(ncol=length(ids),nrow=length(unique(students))))
for(i in 1:length(students)){
for(j in 1:length(ids)){
attempts<-which(scores$question_id==ids[j] &
scores$name==students[i])
if(length(attempts)==0){finaldat[i,j]<-NA}
else{
last.score<-as.numeric(scores$correct[attempts[which(attempts==length(attempts))]])
finaldat[i,j]<-99
if(length(last.score)==0){finaldat[i,j]<-NA}
else{if(last.score==0 | last.score==1){
finaldat[i,j]<-last.score
}
}
}
}
}
finaldat
除了 运行 真的很慢,它不起作用,因为我无法绕过 last.score 行。我确定有一个整洁的 verse 解决方案,但我很难过。任何提示将不胜感激。
所以输出数据将是:
cbind(c(0,1,1),c(99,99,NA),c(1,99,1))
我们可以看到第6题已经被排除,所有非二进制都被转换为99,缺失值是NA,只保留最后的尝试。
这是使用 dplyr
和 tidyr
的版本。
library(dplyr)
library(tidyr)
scores <- data.frame(name = c(1, 2, 3, 3, 1, 2, 3, 1, 2, 1, 2, 3),
question_id = c(5, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8),
correct = c(0, 1, 1, 1, 1, 0, 1, .5 , "fickle", 1, 2.2, 1),
attempt = c(1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1),
stringsAsFactors = FALSE)
result <- scores %>%
group_by(name, question_id) %>%
filter(attempt == max(as.numeric(as.character(attempt)))) %>%
mutate(correct = if(correct != "1" && correct != "0") "99" else correct) %>%
select(name, question_id, correct) %>%
ungroup() %>%
pivot_wider(names_from = question_id, values_from = correct)
result
#> # A tibble: 3 x 5
#> name `5` `6` `7` `8`
#> <dbl> <chr> <chr> <chr> <chr>
#> 1 1 0 1 99 1
#> 2 2 1 0 99 99
#> 3 3 1 1 <NA> 1
只是为了添加另一个解决方案,我已经在努力
library(data.table)
library(dplyr)
library(forcats)
dt.scores <- data.table(scores)
dt.scores[, correct := as.integer(as.character(fct_other(correct, keep = c("0", "1"), other_level = "99"))) ]
dt.scores[, attempt := as.integer(as.character(attempt)) ]
dt.scores[,.(name, question_id, correct)] %>% pivot_wider(data = . , names_from = question_id, values_from = correct, values_fn = list(correct = max))