所以我的数据集看起来像这样,字母表是因子变量。 Pred列用于每个ID的预测观察,Real列是真实的观察。我想计算每个ID的预测值的总体准确性。
ID Pred1 Pred2 Pred3 Real1 Real2 Real3
1 A C E A D B
2 A B D E C C
3 E C A A B D
4 D A B B B D
5 B A C C A B
所以我想改变一个名为'score'的列,它给出了Pred1,2,3和Real1,2,3列之间匹配观察数量的百分比。我只关心在'Real'列中找到任何'Pred'值。如果在Real1,Real2和Real3中找到Pred1,那么我给出1/3的分数。如果Pred1和Pred2(不是Pred3)都在Real1,Real2和Real3列中找到,(*顺序无关紧要。可以在Real2或Real3中找到Pred1-就在'Real'列中的任何位置),然后我给出得分为2/3。我希望这是有道理的。顺序无关紧要,我只关心在'Real'列中查找任何'Pred'值。所以我想要下面这样的东西。
ID Pred1 Pred2 Pred3 Real1 Real2 Real3 Score
1 A C E A D B 1/3
2 A B D E C C 0
3 E C A A B D 1/3
4 D A B B E D 2/3
5 B A C C A B 1
我正在尝试编写一个函数并尝试了类似ifelse(“%1”中的“Pred1”%(“Real1”,“Real2”,“Real3”),1/3,0))但是效果不好... (有强制到逻辑等的错误消息,我不知道如何解决)所以我也在尝试不同的东西,但仍然遇到错误......任何人都可以帮忙吗?先感谢您!
这使得难以比较具有不同因子水平的值。我们可以先将列从因子转换为字符。
df[-1] <- lapply(df[-1], as.character)
找出Predicted和Real列的索引,然后针对每一行检查Real中存在多少个Predicted观察值。
pred_cols <- grep("^Pred", names(df))
real_cols <- grep("^Real", names(df))
df$Score <- sapply(1:nrow(df), function(x)
sum(df[x, pred_cols] %in% df[x, real_cols]))/length(pred_cols)
df
# ID Pred1 Pred2 Pred3 Real1 Real2 Real3 Score
#1 1 A C E A D B 0.33
#2 2 A B D E C C 0.00
#3 3 E C A A B D 0.33
#4 4 D A B B B D 0.67
#5 5 B A C C A B 1.00
由于它是行式比较,我们也可以使用apply
和MARGIN = 1
使用相同的逻辑。使用这种方法,我们不需要将列显式转换为字符。
apply(df, 1, function(x) sum(x[pred_cols] %in% x[real_cols]))/length(pred_cols)
一个tidyverse
可能是:
bind_cols(df %>%
gather(var, val, -matches("(Real|ID)")) %>%
select(ID, val), df %>%
gather(var2, val2, -matches("(Pred|ID)")) %>%
select(val2)) %>%
group_by(ID) %>%
summarise(res = paste0(sum(val %in% val2), "/3")) %>%
left_join(df, by = c("ID" = "ID"))
ID res Pred1 Pred2 Pred3 Real1 Real2 Real3
<int> <chr> <fct> <fct> <fct> <fct> <fct> <fct>
1 1 1/3 A C E A D B
2 2 0/3 A B D E C C
3 3 1/3 E C A A B D
4 4 2/3 D A B B B D
5 5 3/3 B A C C A B
首先,分别将包含Pred
和Real
的列从宽格式转换为长格式。其次,它将两个列组合在一起。最后,按“ID”分组,对匹配案例的数量求和,并将其与原始df连接。
或者如果对的数量不固定为3:
bind_cols(df %>%
gather(var, val, -matches("(Real|ID)")) %>%
select(ID, val), df %>%
gather(var2, val2, -matches("(Pred|ID)")) %>%
select(val2)) %>%
add_count(ID) %>%
group_by(ID) %>%
summarise(res = paste(sum(val %in% val2), first(n), sep = "/")) %>%
left_join(df, by = c("ID" = "ID"))
或者,如果您想要一个数字变量作为结果:
bind_cols(df %>%
gather(var, val, -matches("(Real|ID)")) %>%
select(ID, val), df %>%
gather(var2, val2, -matches("(Pred|ID)")) %>%
select(val2)) %>%
add_count(ID) %>%
group_by(ID) %>%
summarise(res = sum(val %in% val2)/first(n)) %>%
left_join(df, by = c("ID" = "ID"))
ID res Pred1 Pred2 Pred3 Real1 Real2 Real3
<int> <dbl> <fct> <fct> <fct> <fct> <fct> <fct>
1 1 0.333 A C E A D B
2 2 0 A B D E C C
3 3 0.333 E C A A B D
4 4 0.667 D A B B B D
5 5 1 B A C C A B