【问题标题】:How to compare every value from a column from one df with every value from a column of another df in R? dfs with different row numbers如何将来自一个df的列中的每个值与R中另一个df的列中的每个值进行比较?具有不同行号的dfs
【发布时间】:2020-03-09 14:41:38
【问题描述】:

同时考虑盒子和篮子的优先级,哪个盒子适合哪个篮子?

df.boxes 有以下列:
boxID - 盒子的名称
boxX - 盒子的大小X 维度中的框
boxY - Y 维度中框的大小
重要性 - 应首先将哪个框分配给篮子。比如优先级——555 最重要(优先级最高),111 最不重要(优先级最低)

df.basket 有以下列:
basketID - 篮子的名称
basketX - 篮子的大小X 维度中的篮子
basketY - Y 维度中篮子的大小
priorityOfSelection - 哪个篮子应该首先装满盒子。 1 - 最高优先级,7 - 最低优先级

例如,box1 不适合具有最高优先级的篮子,也就是篮子 1,因此它会向下移动到优先级为“2”的下一个篮子,并将其名称存储在 df 的新列“boxes”中。篮子。

我有一个想法,首先我根据它们的“重要性”、“priorotyOfSelection”对两个数据框进行排序,并将框的大小与篮子的大小进行比较,如果匹配,我指定框到相应的篮子。按照这种思维顺序,我正在尝试创建嵌套的 for 循环 - 如您所见,不成功。

谁能指出我做错了什么以及在哪里做错了,或者指导我采用另一种方法,这也将不胜感激?

代表

 df.boxes <-structure(list(boxID = c("box 1", "box 2", "box 3", "box 4", "box 5"), 
                                  boxX = c(600,450, 400, 350, 200), 
                                  boxY = c(600, 400, 450, 500, 300),
                                  importance = c(555, 444, 333, 222, 111) 
                                  ), class = "data.frame", row.names = c(NA, -5L))

df.basket <- structure(list(basketID = c("basket 1", "basket 2", "basket 3","basket 4", "basket 5", "basket 6", "basket 8"), 
                            basketX = c(500,650, 500,200, 450, 500,300),
                            basketY = c(450,650, 500,300,450,500, 300),
                            priorityOfSelection = c(1, 2, 3, 4, 5,6,7) 
                            ), class = "data.frame", row.names = c(NA, -7L))

尝试:

for (i in 1:nrow(df.boxes)){
  for(j in 1:nrow(df.basket)){
  df.basket$box[j] <- ifelse((df.boxes$boxX[i] <= df.basket$basketX[j] | df.boxes$boxY[i] <= df.basket$basketX[j]) & (df.boxes$boxX[i] <= df.basket$basketY[j] | df.boxes$boxY[i] <= df.basket$basketY[j]), 
                                df.boxes$boxID[i], "none")
  }
}

想要的输出:

非常感谢您的宝贵时间!

【问题讨论】:

  • 您可以使用类似的方法来确定一个盒子可以放入哪些篮子,然后因为它们按优先顺序排列,所以只需选择第一个可以放入的篮子。which(df.basket[,"basketX"]&gt;df.boxes[2,"boxX"] &amp; df.basket[,"basketY"]&gt;df.boxes[2,"boxY"])[1]
  • 这可以使其自动化。问题是它会覆盖已经使用过的篮子。 for (i in 1:nrow(df.boxes)){ df.basket[which(df.basket$basketX&gt;df.boxes[i,"boxX"] &amp; df.basket$basketY&gt;df.boxes[i,"boxY"])[1], "box"]&lt;-df.boxes[i,"boxID"] }
  • 感谢您的来信!当我单独运行您的代码时(从第一条评论开始),它可以正确运行到第三个框,并且自动版本让我错误地将框分配到篮子。
  • 那是它覆盖造成的。如果您将 box 列设置为 0,则将其添加为条件,这样它就不会覆盖任何应该修复它的内容。df.basket[,"box"]&lt;-0 for (i in 1:nrow(df.boxes)){ df.basket[which(df.basket$basketX&gt;=df.boxes[i,"boxX"] &amp; df.basket$basketY&gt;=df.boxes[i,"boxY"] &amp; df.basket$box==0)[1], "box"]&lt;-df.boxes[i,"boxID"] } 这给了我与您的示例相同的结果。它为未使用的篮子提供 0 而不是无,但如果需要,您可以轻松更改它。这与@AllanCameron 的建议非常接近。
  • 是的,确实,谢谢@Tanner33,我现在得到了预期的结果! :)

标签: r for-loop left-join subset


【解决方案1】:

如果你在df.boxes中设置了一个额外的列来记录盒子是否被“使用”过,你可以这样做:

df.basket$box <- character(nrow(df.basket))
df.boxes$used <- logical(nrow(df.boxes))

for(i in sort(df.basket$priorityOfSelection))
{
  fits <- which(df.boxes$boxX <= df.basket$basketX[i] &
                df.boxes$boxY <= df.basket$basketY[i] &
                df.boxes$used == FALSE)

  df.basket$box[which(df.basket$priorityOfSelection == i)] <- 
    paste("box", fits[which.max(df.boxes$importance[fits])])
  df.boxes$used[fits[which.max(df.boxes$importance[fits])]] <- TRUE
}

df.basket$box[df.basket$box == "box "] <- "none"

df.basket
#>   basketID basketX basketY priorityOfSelection   box
#> 1 basket 1     500     450                   1 box 2
#> 2 basket 2     650     650                   2 box 1
#> 3 basket 3     500     500                   3 box 3
#> 4 basket 4     200     300                   4 box 5
#> 5 basket 5     450     450                   5  none
#> 6 basket 6     500     500                   6 box 4
#> 7 basket 8     300     300                   7  none

reprex package (v0.3.0) 于 2020-03-09 创建

【讨论】:

  • 哇,谢谢!这似乎很容易,但事实并非如此!但有一件事,可以在篮子内旋转盒子。我扩展了您的fits 向量:fits &lt;- which(((df.boxes$boxX &lt;= df.basket$basketX[i] | df.boxes$boxX &lt;= df.basket$basketY[i] ) &amp; (df.boxes$boxY &lt;= df.basket$basketX[i]| df.boxes$boxY &lt;= df.basket$basketY[i])) &amp; df.boxes$used == FALSE),到目前为止,它仍然给出了与您的结果和期望的结果相同的结果:) 非常感谢!万事如意,-
  • 小心“或”语句。只要篮子的一侧比盒子的两侧长,你写一个盒子的方式就可以放在篮子里。你需要更像 (x
  • fits &lt;- which(((df.boxes$boxX &lt;= df.basket$basketX[i] &amp; df.boxes$boxY &lt;= df.basket$basketY[i] ) | (df.boxes$boxY &lt;= df.basket$basketX[i] &amp; df.boxes$boxX &lt;= df.basket$basketY[i])) &amp; df.boxes$used == FALSE)
【解决方案2】:

只是为了好玩,延迟提交带有“纯for循环”和if,没有额外的列。
假设您基本上要实现的是将盒子从上到下推入(优先排序的)篮子(列表)

df.basket$box <- NA
for (i in seq.int(df.boxes$boxID)){
  for (j in seq.int(df.basket$basketID)){
    if(is.na(df.basket$box[j])){ 
        if (all( c(df.basket$basketX[j], df.basket$basketY[j]) -
                 c(df.boxes$boxX[i], df.boxes$boxY[i]) >= 0)){
            df.basket$box[j] <- df.boxes$boxID[i] 
  break
        }
    }
  }
}
df.basket$box[is.na(df.basket$box)] <- "none" 
df.basket 

    basketID basketX basketY priorityOfSelection   box
1 basket 1     500     450                   1 box 2
2 basket 2     650     650                   2 box 1
3 basket 3     500     500                   3 box 3
4 basket 4     200     300                   4 box 5
5 basket 5     450     450                   5  none
6 basket 6     500     500                   6 box 4
7 basket 8     300     300                   7  none

肯定不像'@Allan Cameron' 的解决方案那样优雅,但也是一种可能的方法,如果你想更好地掌握你在自己尝试中开始使用的for 循环方法。

【讨论】:

  • 很高兴看到我的初始方法以一种能够提供所需输出的方式进行开发。它可能只是前两行代码,但仍然有一个嵌套的 for 循环 :) 非常感谢!
猜你喜欢
  • 2019-11-27
  • 1970-01-01
  • 2021-08-24
  • 2020-09-30
  • 2020-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多