r - 循环导致错误的位置/顺序
问题描述
我需要计算一个非常简单的公式(加权平均值)的结果,该公式使用两个变量(A 和 B)和两个权重因子(A_prop 和 B_prop)。计算将在一个非常大的数据集中进行,权重因子存储在另一个我称之为网格的数据框中。
我的方法是首先为每个权重因子组合创建重复数据,然后进行计算。到此为止没有什么奇怪的。但是后来我想到了计算循环内的值。一切似乎都已经到位,但后来我检查了两种方法的结果,结果不匹配。循环内的计算结果不正确。
我知道我应该相处并坚持给我正确结果的那个,也是因为行数很少。没什么大问题。但是......我可以忍受这个。我快要扯断我的头发了。
谁能解释一下为什么结果不一样?循环计算有什么问题?此外,如果您有任何关于更优雅的建议,也将受到欢迎。
(注意:我第一次使用reprex。希望它是应该的)
>require(tidyverse)
>require(magicfor)
>require(readxl)
>require(reprex)
> dput(dt)
structure(list(X = 1:5, A = c(83.73, 50.4, 79.59, 62.96, 0),
B = c(100, 86.8, 80.95, 81.48, 0), weight = c(201.6, 655,
220.5, 280, 94.5), ind = c(733L, 26266L, 6877L, 8558L, 16361L
)), class = "data.frame", row.names = c(NA, -5L))
> dput(grid)
structure(list(A_prop = c(0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8,
0.85, 0.9, 0.95, 1), B_prop = c(0.5, 0.45, 0.4, 0.35, 0.3, 0.25,
0.2, 0.15, 0.1, 0.05, 0), id = 1:11, tag = structure(1:11, .Label = c("Aprop_0.5",
"Aprop_0.55", "Aprop_0.6", "Aprop_0.65", "Aprop_0.7", "Aprop_0.75",
"Aprop_0.8", "Aprop_0.85", "Aprop_0.9", "Aprop_0.95", "Aprop_1"
), class = "factor")), class = "data.frame", row.names = c(NA,
-11L))
> foo<-function(data,i){
+ val<-(data$A*grid[i,1])+(data$B*grid[i,2])
+ return(val)
+ }
> magic_for(print, progress=FALSE,silent = TRUE)
> for(i in grid$id){
+
+ score<-(dt$A*grid[i,1])+(dt$B*grid[i,2])
+
+ weight=dt$weight
+ A<-dt$A
+ B<-dt$B
+
+ ind=dt$ind
+
+ print(score)
+ print(weight)
+ print(ind)
+ print(A)
+ print(B)
+ }
> rest<-magic_result_as_dataframe()
> magic_free()
> rest2<-left_join(rest,grid,by=c("i"="id"))%>%
+ arrange(ind,tag)%>%
+ mutate(score2=(A*A_prop)+(B*B_prop))
> head(rest2)
i score weight ind A B A_prop B_prop tag score2
1 1 91.8650 201.6 733 83.73 100 0.50 0.50 Aprop_0.5 91.8650
2 2 84.5435 201.6 733 83.73 100 0.55 0.45 Aprop_0.55 91.0515
3 3 86.1705 201.6 733 83.73 100 0.60 0.40 Aprop_0.6 90.2380
4 4 87.7975 201.6 733 83.73 100 0.65 0.35 Aprop_0.65 89.4245
5 5 89.4245 201.6 733 83.73 100 0.70 0.30 Aprop_0.7 88.6110
6 6 91.0515 201.6 733 83.73 100 0.75 0.25 Aprop_0.75 87.7975
解决方案
问题实际上是你的 left_join 而不是 for 循环。对于以后的帖子,我建议您还提供一个最小(istic)示例。
我将演示您的代码中出了什么问题。
比如说,我们有这些数据框,它们应该与您的真实数据相似:
dt <- data.frame(
A = c(2,3,4),
B = c(20,30,40)
)
grid <- data.frame(
A_prop = c(0.5, 0.6),
B_prop = c(0.5, 0.4),
id = c(1,2),
tag = c("A_prop0.5", "A_prop0.6"))
我们期望以下输出:
预期输出 dt[1,] & A_prop 0.5 和 B_prop 0.5
2 * 0.5 + 20 * 0.5 #= 11
预期输出 dt[2,] & A_prop 0.5 和 B_prop 0.5
3 * 0.5 + 30 * 0.5 #= 16.5
预期输出 dt[3,] & A_prop 0.5 和 B_prop 0.5
4 * 0.5 + 40 * 0.5 #= 22
预期输出 dt[1,] & A_prop 0.6 和 B_prop 0.4
2 * 0.6 + 20 * 0.4 #= 9.2
预期输出 dt[1,] & A_prop 0.6 和 B_prop 0.4 3 * 0.6 + 30 * 0.4 #= 13.8
预期输出 dt[1,] & A_prop 0.6 和 B_prop 0.4
4 * 0.6 + 40 * 0.4 #= 18.4
我从未使用过“magicfor”库,但问题在于您的加入方式i
和id
.
我将编写for循环如下:
l <- list()
for(i in grid$id){
score<-(dt$A*grid[i,1])+(dt$B*grid[i,2])
A<-dt$A
B<-dt$B
iteration <- rep(i, 3) # to keep track in which iteration the result was created.
l[[i]] <- list(
score = score,
A = A,
B = B,
iteration = iteration
)
}
现在,我将列表绑定到数据框并按照您在示例中所做的那样执行 left_join:
l <- bind_rows(l)
l_merged <- grid %>% left_join(l, by = c("id"="iteration")) %>%
mutate(score2 = (A*A_prop + B*B_prop))
score 和 score2 相同的测试:
transmute(l_merged, identical = score == score2)
identical
1 TRUE
2 TRUE
3 TRUE
4 TRUE
5 TRUE
6 TRUE
现在到实际问题
我已经稍微修改了你的代码。我已将迭代次数添加到输出中。
magic_for(print, progress=FALSE,silent = TRUE)
for(i in grid$id){
score<-(dt$A*grid[i,1])+(dt$B*grid[i,2])
A<-dt$A
B<-dt$B
iteration <- rep(i, 3)
print(score)
print(A)
print(B)
print(iteration)
}
rest<-magic_result_as_dataframe()
magic_free()
现在,如果我们查看输出并比较i
和iteration
,我们可以看到它们并不相同。因此,您left_join()
产生了令人困惑的结果。
rest %>% arrange(i)
i score A B iteration
1 1 11.0 2 20 1
2 1 22.0 4 40 1
3 1 13.8 3 30 2
4 2 16.5 3 30 1
5 2 9.2 2 20 2
6 2 18.4 4 40 2
最后,我们可以对其进行测试:
grid %>% left_join(rest, by = c("id"="i")) %>% # using i for the join
mutate(score2 = (A*A_prop + B*B_prop)) %>%
transmute(identical = score == score2)
identical
1 TRUE
2 TRUE
3 FALSE
4 FALSE
5 TRUE
6 TRUE
加入 withi
不会产生正确的结果。
但是加入iteration
will:
grid %>% left_join(rest, by = c("id"="iteration")) %>% # using the "manually" produced iteration for the join
mutate(score2 = (A*A_prop + B*B_prop)) %>%
transmute(identical = score == score2)
identical
1 TRUE
2 TRUE
3 TRUE
4 TRUE
5 TRUE
6 TRUE
我不确定为什么i
from "magicfor" 不同于手动创建的iteration
. 我当然明白你的困惑...