根据R中的多个列值创建值序列

时间:2019-07-18 22:39:14

标签: r dplyr data.table

我有一个data.frame,它是点的近邻搜索的结果,它有三列:V1代表最近点的索引,V2代表第二个最近点,V3代表第三点:

search_result <- structure(list(V1 = c(1350L, 1390L, 1411L, 1437L, 1444L, 1895L, 
                                       1895L, 1467L, 1478L, 1500L), 
                                V2 = c(1351L, 1391L, 1410L, 1438L, 
                                       1907L, 1456L, 1456L, 1466L, 1477L, 1499L), 
                                V3 = c(1349L, 1389L, 1940L, 1913L, 1445L, 1894L, 
                                       1894L, 1884L, 1479L, 1501L)), 
                           row.names = c(NA, -10L), 
                           class = "data.frame")

因为我想要最近的邻居点,所以我选择V1作为结果,我会好的。碰巧我也希望对索引进行排序,并且V1的某些索引不正确。因此,我想创建一列,该列将为我提供V1的值(按顺序排列)或V2或V3的值(以V2为优先顺序),以便保留订单。在这种情况下,结果将是:

     V1   V2   V3 ordered
1  1350 1351 1349    1350
2  1390 1391 1389    1390
3  1411 1410 1940    1411
4  1437 1438 1913    1437
5  1444 1907 1445    1444
6  1895 1456 1894    1456 #take V2 instead
7  1895 1456 1894    1456 #take V2 instead
8  1467 1466 1884    1467
9  1478 1477 1479    1478
10 1500 1499 1501    1500

我尝试获取每列的最小值,但是在数据集的某些情况下,最大值将是期望的(不是最佳选择,而是更接近期望值)。在下面的示例中,第2、4、5和6行不连续,因此我将根据需要选择V2(优先级)或V3的值,因此维持“顺序”:

# it's harder to see the "order" here, but it starts in V1 = 1881

   V1   V2   V3  ordered
1 1881 1470 1880    1881
2 1457 1893 1894    1893 #take V2 instead
3 1907 1444 1906    1907
4 1442 1443 1908    1908 #take V3 instead
5 1433 1918 1432    1918 #take V2 instead
6 1402 1949 1401    1949 #take V2 instead
7 1968 1969 1967    1968
8 1985 1986 1984    1985
9 1992 1993 1991    1992

完整的数据集有2500个点,“无序”值大约占其中的10%,因此我可以估计什么是“有序”。

任何base tidyversedata.table帮助将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:1)

听起来您想要做的是遍历搜索返回的每一列,并首先遍历每一行,并保持顺序满足索引的第一个值。

首先假设第一列是按顺序排列的。移动到第二列并替换所有不正确的行。与更新后的有序列比较,移至第三列。继续所有列。

可能有一种更优化的编码方式(例如,在迭代所有列之前检查答案是否收敛),但这是实现此目的的紧凑方式(请注意,lag函数是{{ 1}}不是dplyr::lag):

stats::lag

如果不确定最近的邻居搜索是否返回了足够多的列,则必须再添加一次迭代以检查有序列是否在递增

library(dplyr)
library(purrr)

# using the second data set
# assuming at least one column will satisfy the constraints
data.frame(
  V1 = c(1881, 1457, 1907, 1442, 1433, 1402, 1968, 1985, 1992),
  V2 = c(1470, 1893, 1444, 1443, 1918, 1949, 1969, 1986, 1993),
  V3 = c(1880, 1894, 1906, 1908, 1432, 1401, 1967, 1984, 1991)
) %>%
  dplyr::mutate(
    ordered = reduce(., ~ifelse(.x >= lag(.x, default = 0), .x, .y))
  )

#>     V1   V2   V3 ordered
#> 1 1881 1470 1880    1881
#> 2 1457 1893 1894    1893
#> 3 1907 1444 1906    1907
#> 4 1442 1443 1908    1908
#> 5 1433 1918 1432    1918
#> 6 1402 1949 1401    1949
#> 7 1968 1969 1967    1968
#> 8 1985 1986 1984    1985
#> 9 1992 1993 1991    1992

reprex package(v0.3.0)于2019-07-19创建

答案 1 :(得分:1)

由于V1应该一直在增加,因此我们可以将V1的第一个值作为参考,并以此first_value从第二行中减去所有值,然后取最小值区别。既然如此,我们还想考虑优先级的一种方法是将差异乘以增量数。在此示例中,我将其乘以整数1、2和3。因此,第一个差乘以1,然后乘以2,依此类推。如果发现一些边缘情况,可以考虑使用更复杂的方法来分配优先级。

first_value <- search_result$V1[1]
search_result$ordered <- c(first_value, apply(search_result[-1, ], 1, function(x) {
     x <- x[x > first_value]
     x[which.min((x - first_value) * seq_along(x))]
}))

search_result
#     V1   V2   V3 ordered
#1  1350 1351 1349    1350
#2  1390 1391 1389    1390
#3  1411 1410 1940    1411
#4  1437 1438 1913    1437
#5  1444 1907 1445    1444
#6  1895 1456 1894    1456
#7  1895 1456 1894    1456
#8  1467 1466 1884    1467
#9  1478 1477 1479    1478
#10 1500 1499 1501    1500

这也适用于第二个数据集,将其视为df

first_value <- df$V1[1]
df$ordered <- c(first_value, apply(df[-1, ], 1, function(x) {
     x <- x[x > first_value]
     x[which.min((x - first_value) * seq_along(x))]
}))

df
#    V1   V2   V3 ordered
#1 1881 1470 1880    1881
#2 1457 1893 1894    1893
#3 1907 1444 1906    1907
#4 1442 1443 1908    1908
#5 1433 1918 1432    1918
#6 1402 1949 1401    1949
#7 1968 1969 1967    1968
#8 1985 1986 1984    1985
#9 1992 1993 1991    1992