如何有条件地按行比较数据行并将不同的结果输出到其他列?

时间:2017-06-22 04:54:17

标签: r vectorization

如何有条件地按行比较数据行并将不同的结果输出到其他列?

请参阅下面的dataset

第1行的den为1,开始将每行的权重与第1行的权重进行比较,将每行的体积与第1行的体积进行比较。

首先检查某行的Weight是否高于第1行的权重,第1行的higher列将变为1,否则检查某行的Volume是否为比第1行的Volume低1.0,第1行的下一列将变为1。

在满足其中任何一个条件之前,继续比较下一行和下一行......如果第2行满足任一条件,则转到第3行,如果符合Row的任一条件3,继续行到第4行.....等等。

如果满足其中一个条件(第1行的higherlower列之一== 1),请转到den==1第3行的下一行在这种情况下。第6行。

{1}}列用于记录第1行' s {{1}时行howhigh与第1行' s Weight之间的差异}。 Weight列用于记录满足条件的行差异(例如:在higher == 1中,第1行' s between为5,因为条件符合第6行的要求,所以Expected Outcome,第3行的between为3,因为条件符合第6行所以6 - 1 = 5

然后between会变成6 - 3 = 3

dataset获取第14行,Expected Outcome,因为第18行的Expected Outcome更高。 higher==1Weight,因为第14行和第18行的howhigh差异为0.0649Weight0.0649,因为between

如何实现这种矢量化方式来提高计算速度? 提前致谢。

数据集

4

预期结果

18-14=4

1 个答案:

答案 0 :(得分:2)

我抓住了这个。让我知道速度如何,因为它不是100%矢量化解决方案。我花了一段时间才明白你只想看看书房下方的行,如果音量较低,你并不意味着低于1.0,而是等于或小于1.0。

# Your data
dat <- structure(list(Weight = c(5.1626, 5.1615, 5.16, 5.1593, 5.1592, 5.1635, 5.1608, 5.1602, 5.1582, 5.1563, 5.1578, 5.1589, 5.1578, 5.1591, 5.1585, 5.1572, 5.1565, 5.224, 5.154, 5.1539, 5.152, 5.145, 5.1455, 5.1461, 5.147, 5.1449, 5.1423, 6.1429, 5.1425, 5.1433), Volume = c(5.1594, 5.1559, 5.1574, 5.1582, 5.1572, 5.158, 5.158, 4.0565, 5.1554, 5.1547, 5.155, 5.156, 3.1553, 5.1554, 5.1563, 5.1557, 5.152, 5.1518, 5.1505, 5.1488, 5.1408, 5.142, 5.142, 5.1435, 5.1437, 5.1378, 5.1385, 5.1401, 5.1399, 5.1403), den = c(1L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L), higher = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), lower = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), between = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), howhigh = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L)), .Names = c("Weight", "Volume", "den", "higher", "lower", "between", "howhigh"), class = "data.frame", row.names = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30"))

我在data.frame中添加了一个rownumber,以便在apply中更方便地访问,然后我只使用den == 1的行来创建一个用于循环的新变量。

dat$rownum <- 1:nrow(dat)
newd <- dat[dat$den == 1,]
#   Weight Volume den higher lower between howhigh rownum
#1  5.1626 5.1594   1      1     0       0       0      1
#3  5.1600 5.1574   1      1     0       0       0      3
#6  5.1635 5.1580   1      1     0       0       0      6
#11 5.1578 5.1550   1      1     0       0       0     11
#14 5.1591 5.1554   1      1     0       0       0     14
#19 5.1540 5.1505   1      1     0       0       0     19
#30 5.1433 5.1403   1      1     0       0       0     30

功能:

out <- t(apply(newd, 1, function(d){
  rownum <- d["rownum"]
  a <- which(dat$Weight > d["Weight"])
  a <- a[a > rownum][1]
  b <- which((dat$Volume - d["Volume"]) <= -1.0)
  b <- b[b > rownum][1]
  pick <- ifelse(!is.na(b), ifelse(a < b, "a", "b"), "a")
  if( pick == "a"){
    d["higher"] <- 1
    d["howhigh"] <- dat$Weight[a] - d["Weight"]
    d["between"] <- a - rownum
  } else {
    d["lower"] <- 1
    d["between"] <- b - rownum
  }
  d[is.na(d)] <- 0
  d
}))
out
#   Weight Volume den higher lower between howhigh rownum
#1  5.1626 5.1594   1      1     0       5  0.0009      1
#3  5.1600 5.1574   1      1     0       3  0.0035      3
#6  5.1635 5.1580   1      0     1       2  0.0000      6
#11 5.1578 5.1550   1      1     0       1  0.0011     11
#14 5.1591 5.1554   1      1     0       4  0.0649     14
#19 5.1540 5.1505   1      1     0       9  0.9889     19
#30 5.1433 5.1403   1      1     0       0  0.0000     30

dat[dat$den == 1,] <- out # replace old rows with new ones
dat[,-8] # remove the rownum column