首页 > 解决方案 > 循环导致错误的位置/顺序

问题描述

我需要计算一个非常简单的公式(加权平均值)的结果,该公式使用两个变量(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

标签: rloopsfor-loop

解决方案


问题实际上是你的 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”库,但问题在于您的加入方式iid.

我将编写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()

现在,如果我们查看输出并比较iiteration,我们可以看到它们并不相同。因此,您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不会产生正确的结果。

但是加入iterationwill:

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

我不确定为什么ifrom "magicfor" 不同于手动创建的iteration. 我当然明白你的困惑...


推荐阅读