简体   繁体   English

使用 r base function 找到矩阵中每一行的相对最小值,但每个最小值在不同的列

[英]use r base function to find the relatively min value of each row in matrix but each min value at different column

I have a matrix like this我有一个这样的矩阵

d <- matrix(c(10, -20, -30, 20, 30,
              10, -15, -30, 20, 30,
              10, 40, -30, 20, 30,
              10, -20, -30, 20, 40), byrow = TRUE, nrow = 4)

# > d
#      [,1] [,2] [,3] [,4] [,5]
# [1,]   10  -20  -30   20   30
# [2,]   10  -15  -30   20   30
# [3,]   10   40  -30   20   30
# [4,]   10  -20  -30   20   40

I want to find the index of each row min value whose abs value is less equal 25, but each row min value should at different column.我想找到 abs 值小于 25 的每一行最小值的索引,但每一行最小值应该在不同的列。 I use for loop to do it like this, which is not good enough.我使用 for 循环来做到这一点,这还不够好。

rng <- 25
ok <- abs(d) < rng
res <- rep(NA, 4)
for (i in seq_len(nrow(d))) {
    if (any(ok[i, ])) {
        dd <- d[i, ]
        idx <- which(ok[i, ])
        idx.min <- idx[which.min(dd[idx])]
        res[i] <- idx.min
        ok[, idx.min] <- FALSE
    }
}
res

the result is this结果是这样的

# > res
# [1]  2  1  4 NA

which means that the index of the first row is 2, whose value is -20.这意味着第一行的索引为2,其值为-20。 and since the second column is used, although the min value of the second row is still in the second column, it should be the first column value 10, and the index is 1. If it can not find the min value, the index is NA.并且由于使用了第二列,虽然第二行的最小值还在第二列,但应该是第一列值10,索引为1。如果找不到最小值,则索引为不适用。

Is there vectorizing function that can do this?是否有矢量化 function 可以做到这一点? thanks guys.多谢你们。 If there is any English expression problem, please also tell me.如果有任何英文表达问题,也请告诉我。

If you want to get the column index with the minimal absolute value for each row, you can do:如果要获取每行绝对值最小的列索引,可以执行以下操作:

library(tidyverse)

d <- matrix(c(
  10, -20, -30, 20, 30,
  10, -15, -30, 20, 30,
  10, 40, -30, 20, 30,
  10, -20, -30, 20, 40
), byrow = TRUE, nrow = 4)

d %>%
  as_tibble(rownames = "row") %>%
  pivot_longer(-row, names_to = "col") %>%
  mutate(col = col %>% str_extract("[0-9]+") %>% as.numeric()) %>%
  group_by(row) %>%
  # only consider values with small abs volaue
  filter(abs(value) < 25) %>%
  # get the smallest value
  arrange(abs(value)) %>%
  slice(1) %>%
  # get column indicies
  pull(col)
#> Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of tibble 2.0.0.
#> Using compatibility `.name_repair`.
#> [1] 1 1 1 1

Created on 2021-12-07 by the reprex package (v2.0.1)reprex package (v2.0.1) 于 2021 年 12 月 7 日创建

Is this your expected result?这是你预期的结果吗?

Here is a base R way.这是一个基本的 R 方式。 It sets each value in the columns already in ok and each value not less than rng to Inf .它将列中的每个值设置为ok并且每个值不小于rngInf And uses which.min to find the minima per row.并使用which.min找到每行的最小值。

rng <- 25
ok <- rep(NA_integer_, nrow(d))
for(i in seq_len(nrow(d))) {
  x <- abs(d[i,])
  x[ok] <- Inf
  x[x >= rng] <- Inf
  if(any(is.finite(x))) ok[i] <- which.min(x)
}

ok
#[1]  1  2  4 NA

You can try for loop like below您可以尝试像下面这样for循环

res <- c()
for (i in 1:nrow(d)) {
  v <- d[i, ]
  idx <- abs(v) <= 25 & !(1:ncol(d) %in% res)
  if (all(!idx)) {
    res <- c(res, NA)
  } else {
    res <- c(res, which(v == min(v[idx])))
  }
}

and you will see你会看到

> res
[1]  2  1  4 NA

Here's an option that removes the chosen column at each iteration.这是一个在每次迭代中删除所选列的选项。

d <- matrix(c(10, -20, -30, 20, 30,
              10, -15, -30, 20, 30,
              10, 40, -30, 20, 30,
              10, -20, -30, 20, 40), byrow = TRUE, nrow = 4)

d[abs(d) > 25] <- NA
res <- integer(nrow(d))
# rbind the column index
d <- rbind(1:ncol(d), d)

for (i in 2:nrow(d)) {
  idx <- which.min(d[i,])
  
  if (length(idx)) {
    res[i - 1L] <- d[1, idx]
    d <- d[, -idx]
  } else {
    res[i - 1L] <- NA
  }
}

res
#> [1]  2  1  4 NA

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM