2016-06-13 40 views
1

假设我有数据如下,计算三个列中最小的差和中的R得到相应的列名

data 

required_value   Value1   Value2  Value3 
    0.5     .1    0.3   0.4 
    1.0     1    0.7   0.2 
    1.5     .37    0.3   0.7 
    2.0     1.25   0.9   1.9 

我想找到该三列(值1,值2,值3)的是最接近所需值并创建一个新列并具有该列的列名。我的示例输出,

数据

required_value   Value1   Value2  Value3  output 
    0.5     .1    0.3   0.4  Value3 
    1.0     1    0.7   0.2  Value1 
    1.5     .37    0.3   0.7  Value3 
    2.0     1.25   0.9   1.9  Value3 

我能够发现这个衣柜值。但无法获得相应的列名称。有人能帮我做这件事吗?

谢谢

+0

你是怎么找到最接近的价值?那段代码似乎缺失了。 – hrbrmstr

回答

3

发布这个答案,看起来像一个家庭作业,对我的判断更好。

read.table(text="required_value   Value1   Value2  Value3 
    0.5     .1    0.3   0.4 
    1.0     1    0.7   0.2 
    1.5     .37    0.3   0.7 
    2.0     1.25   0.9   1.9", header=TRUE) -> df 


df$output <- apply(df, 1, function(x) { 
    names(x)[which.min(abs(x[2:4] - x[1]))+1] 
}) 

## required_value Value1 Value2 Value3 output 
## 1   0.5 0.10 0.3 0.4 Value3 
## 2   1.0 1.00 0.7 0.2 Value1 
## 3   1.5 0.37 0.3 0.7 Value3 
## 4   2.0 1.25 0.9 1.9 Value3 

UPDATE:

我知道sweep()有很多代码克鲁夫特在里面,但是,哇:

Unit: microseconds 
    expr  min  lq  mean median  uq  max neval 
apply 83.281 103.156 117.414 113.479 126.790 256.216 100 
sweep 1116.052 1194.766 1292.346 1218.801 1301.724 2309.745 100 

enter image description here

3

可以打破这种下降到?max.col操作,后扫除了第一列和其余列之间的差异:

names(df[-1])[max.col(-abs(sweep(df[-1], 1, df$required_value)),"first")] 
#[1] "Value3" "Value1" "Value3" "Value3" 

要解决@hrbrmstr的基准,显示这是慢的。是的,当数据量很小时,它会比较慢,因为函数的开销会多花几微秒。但是,这段代码应该缩放,以便在小数据上丢失几分之一秒时,随着大小的增加,它将运行得更快。在例如计时:

-sweep/max.col 
      user system elapsed 
10k  0.00 0.00 0.00 
100k  0.17 0.01 0.19 
1M   1.36 0.12 1.49 
5M   3.99 0.59 4.58 

-apply 
      user system elapsed 
10k  0.05 0.00 0.05 
100k  0.56 0.00 0.57 
1M   7.33 0.08 7.41 
5M  41.36 0.13 41.52 
+0

哇,我没有想到基准是那么多不同,但他们是。 – hrbrmstr

+0

@hrbrmstr - 尝试使用大于4行的行 - 当数据变大时,'max.col/sweep'会更快 - 尝试100K或1M行。对于1M扫描是1.5秒,对于7.4秒是适用的。 1000微秒是0.001秒,如果你只有小数据可能不值得冒汗。 – thelatemail

1

您也可以从广从数据到长格式,然后筛选出具有所需的值最小差的变量:

library(data.table) 
data$id <- seq_len(nrow(data)) # create an id variable for group by operation 
longData <- melt(data, id.vars = c("id", "required_value")) # transform to long format 
data[longData[, .(variable[which.min(abs(value - required_value))]) ,.(id)], on = "id"] 

    required_value Value1 Value2 Value3 id  V1 
1:   0.5 0.10 0.3 0.4 1 Value3 
2:   1.0 1.00 0.7 0.2 2 Value1 
3:   1.5 0.37 0.3 0.7 3 Value3 
4:   2.0 1.25 0.9 1.9 4 Value3