我正在计算课程的最终平均分。大约有500名学生,成绩被组织成.csv
个文件。列标题包括:
Name, HW1, ..., HW10, Quiz1, ..., Quiz5, Exam1, Exam2, Final
每个都有不同的加权,这不应该是编程问题。但是,每个学生都会删除最低的2个HW和最低的测验。我怎么能在r中编程呢?请注意,为每个学生删除的HW /测验可能不同(即学生A有HW2,HW5,Quiz2掉线,学生B有HW4,HW8,Quiz1掉线)。
答案 0 :(得分:3)
这是一个更简单的解决方案。 sum_after_drop
函数采用向量x
并降低i
最低分数并总结其余分数。我们为数据集中的每一行调用此函数。 ddply
对于这项工作来说太过分了,但要保持简单。您应该可以使用apply
执行此操作,但必须将最终结果转换为数据框。
然后可以在dd2
上执行实际成绩计算。请注意,将cut
函数与breaks
一起使用是从总分中获得字母成绩的简单方法。
library(plyr)
sum_after_drop <- function(x, i){
sum(sort(x)[-(1:i)])
}
dd2 = ddply(dd, .(Name), function(d){
hw = sum_after_drop(d[,grepl("HW", nms)], 1)
qz = sum_after_drop(d[,grepl("Quiz", nms)], 1)
data.frame(hw = hw, qz = qz)
})
答案 1 :(得分:2)
这是一个如何使用reshape2包和基本函数来处理它的草图。
#sample data
set.seed(734)
dd<-data.frame(
Name=letters[1:20],
HW1=rpois(20,7),
HW2=rpois(20,7),
HW3=rpois(20,7),
Quiz1=rpois(20,15),
Quiz2=rpois(20,15),
Quiz3=rpois(20,15)
)
现在我将其转换为长格式并拆分字段名称
require(reshape2)
mm<-melt(dd, "Name")
mm<-cbind(mm,
colsplit(gsub("(\\w+)(\\d+)","\\1:\\2",mm$variable, perl=T), ":",
names=c("type","number"))
)
现在,我可以使用by()
获取每个名称的data.frame并执行其余计算。在这里,我只放下最低的作业和最低的测验,我给作业重量为.2,并测试重量为.8(假设所有家庭作品价值15分,测验25分)。
grades<-unclass(by(mm, mm$Name, function(x) {
hw <- tail(sort(x$value[x$type=="HW"]), -1);
quiz <- tail(sort(x$value[x$type=="Quiz"]), -1);
(sum(hw)*.2 + sum(quiz)*.8) / (length(hw)*15*.2+length(quiz)*25*.8)
}))
attr(grades, "call")<-NULL #get rid of crud from by()
grades;
让我们检查一下我们的工作。看看学生&#34; c&#34;
Name HW1 HW2 HW3 Quiz1 Quiz2 Quiz3
c 6 9 7 21 20 14
他们的成绩应该是
((9+7)*.2+(21+20)*.8) / ((15+15)*.2 + (25+25)*.8) = 0.7826087
事实上,我们看到了
grades["c"] == 0.7826087
答案 2 :(得分:0)
以下是dplyr
的解决方案。它按学生和作业类型对分数进行排名(即计算所有学生1作业的等级顺序等),然后筛选出最低的1(或2,或其他)。 dplyr
的语法非常直观 - 您应该可以非常轻松地浏览代码。
# Load libraries
library(reshape2)
library(dplyr)
# Sample data
grades <- data.frame(name=c("Sally", "Jim"),
HW1=c(10, 9),
HW2=c(10, 5),
HW3=c(5, 10),
HW4=c(6, 9),
HW5=c(8, 9),
Quiz1=c(9, 5),
Quiz2=c(9, 10),
Quiz3=c(10, 8),
Exam1=c(95, 96))
# Melt into long form
grades.long <- melt(grades, id.vars="name", variable.name="graded.name") %.%
mutate(graded.type=factor(sub("\\d+","", graded.name)))
grades.long
# Remove the lowest scores for each graded type
grades.filtered <- grades.long %.%
group_by(name, graded.type) %.%
mutate(ranked.score=rank(value, ties.method="first")) %.% # Rank all the scores
filter((ranked.score > 2 & graded.type=="HW") | # Ignore the lowest two HWs
(ranked.score > 1 & graded.type=="Quiz") | # Ignore the lowest quiz
(graded.type=="Exam"))
grades.filtered
# Calculate the average for each graded type
grade.totals <- grades.filtered %.%
group_by(name, graded.type) %.%
summarize(total=mean(value))
grade.totals
# Unmelt, just for fun
final.grades <- dcast(grade.totals, name ~ graded.type, value.var="total")
final.grades
从技术上讲,您可以将summarize(total=mean(value))
添加到grades.filtered
数据框,而不是制作单独的grade.totals
数据框 - 出于教学原因,我将它们分成多个数据框。