来自数据表的R最小值不等于特定值

时间:2016-01-30 08:58:11

标签: r minimum

  1. 如何从R数据表中找到特定值以外的最小值?

    例如,数据表中可能存在零,目标是找到最小非零值。

    我尝试将sapplymin一起使用,但我不确定如何指定我们拥有的额外条件,以使最小值不等于某个值。

  2. 更一般地说,我们如何从数据表中找到不等于可能值列表中任何元素的最小值?

3 个答案:

答案 0 :(得分:5)

如果您希望在排除该向量中的某些值时从向量中找到最小值,则可以使用%in%

v <- c(1:10)           # values 1 .. 10
v.exclude <- c(1, 2)   # exclude the values 1 and 2 from consideration
min.exclude <- min(v[!v %in% v.exclude])

如果您使用数据表/框架中的列,则逻辑不会发生太大变化。在这种情况下,您可以使用适当的列替换向量v。如果列表中包含排除的值,则可以展平它以生成v.exclude向量。

答案 1 :(得分:2)

假设您正在使用data.frame

数据

df <- data.frame(a = c(0,2,3,2,1,2,3,4,5,6),
                 b = c(10,10,20,20,30,30,40,40,50,60))

从我们的最小搜索中排除的值

exclude <- c(0,1,2,3)

我们可以找到列a的最小值,不包括我们的exclude向量

## minimum from column a
min(df[!df$a %in% exclude,]$a)
# [1] 4

或来自b

exclude <- c(10, 20, 30, 40)
min(df[!df$b %in% exclude,]$b)
# [1] 50

返回与最小值对应的行

df[df$b == min( df[ !df$b %in% exclude, ]$b ),]
#   a  b
# 9 5 50

<强>更新

要找到多行的最小值,我们可以这样做:

## values to exclude
exclude_a <- c(0,1)
exclude_b <- c(10)

## exclude rows/values from each column we don't want
df2 <- df[!(df$a %in% exclude_a) & !(df$b %in% exclude_b),]

## order the data 
df3 <- df2[with(df2, order(a,b)),]

## take the first row
df3[1,]
# > df3[1,]
# a  b
#4 2 20

更新2

要从多个列中进行选择,我们可以在@akrun显示时对其进行迭代,或者我们可以使用expressioneval在我们的[操作中构建我们的子集公式

exclude <- c(0,1,2, 10)

## construct a formula/expression using the column names
n <- names(df)
expr <- paste0("(", paste0(" !(df$", n, " %in% exclude) ", collapse = "&") ,")")
# [1] "( !(df$a %in% exclude) & !(df$b %in% exclude) )"
expr <- parse(text=expr)

df2 <- df[eval(expr),]

## order and select first row as before
df2 <- df2[with(df2, order(a,b)),]
df2 <- df2[1,]

如果我们想使用data.table

library(data.table)
setDT(df)[ eval(expr) ][order(a, b),][1,]

比较方法

library(microbenchmark)

fun_1 <- function(x){
  df2 <- x[eval(expr),]

  ## order and select first row as before
  df2 <- df2[with(df2, order(a,b)),]
  df2 <- df2[1,]
  return(df2)
}

fun_2 <- function(x){
  df2 <- setDT(x)[ eval(expr) ][order(a, b),][1,]
  return(df2)
}

## including @akrun's solution
fun_3 <- function(x){
  setDT(df)
  MinVal <- vector('list', length(df))
  for(j in seq_along(df)){
    setkeyv(df, names(df)[j])
    MinVal[[j]] <- min(df[!.(exclude)][[j]])
  }
  return(MinVal)
}

microbenchmark(fun_1(df), fun_2(df), fun_3(df) , times=1000)
 # Unit: microseconds
 #     expr      min        lq      mean   median        uq      max neval
 # fun_1(df)  770.376  804.5715  866.3499  833.071  869.2195 2728.740  1000
 # fun_2(df)  854.862  893.1220  952.1207  925.200  962.6820 3115.119  1000
 # fun_3(df) 1108.316 1148.3340 1233.1268 1186.938 1234.3570 5400.544  1000

答案 2 :(得分:2)

在设置data.table

之后,可以使用key(正如OP提到的关于帖子中数据表的内容)来完成此操作
library(data.table)
setDT(df, key='a')[!.(exclude)]
#   a  b
#1: 4 40
#2: 5 50
#3: 6 60

如果我们需要'{'

min
min(setDT(df, key='a')[!.(exclude)]$a)
#[1] 4

为了在所有列中找到min(使用setkey方法),我们遍历数据集的列,将键设置为每个列,将数据集的子集,获取先前创建的min对象中的list值。

setDT(df)
MinVal <- vector('list', length(df))
for(j in seq_along(df)){
 setkeyv(df, names(df)[j])
 MinVal[[j]] <- min(df[!.(exclude)][[j]])
}

MinVal
#[[1]]
#[1] 4

#[[2]]
#[1] 10

数据

df <- data.frame(a = c(0,2,3,2,1,2,3,4,5,6),
             b = c(10,10,20,20,30,30,40,40,50,60))
exclude <- c(0,1,2,3)