将向量从二进制强制转换为“as.numeric”时保留名称?
Posted
技术标签:
【中文标题】将向量从二进制强制转换为“as.numeric”时保留名称?【英文标题】:Preserve names when coercing vector from binary to `as.numeric`? 【发布时间】:2016-10-23 09:38:43 【问题描述】:在 R 中,当您将向量从二进制强制转换为数字时,名称会被删除。
我之前已经概述了一些可能的解决方案。通过将 0 添加到所有值来依赖隐式转换似乎很危险,并且sapply()
为我的操作添加了一个额外的循环(这似乎效率低下)。使用as.numeric
转换向量时,还有其他方法可以保留名称吗?
# Set the seed
set.seed(1045)
# Create a small sample vector and give it names
example_vec <- sample(x = c(TRUE,FALSE),size = 10,replace = TRUE)
names(example_vec) <- sample(x = LETTERS,size = 10,replace = FALSE)
example_vec
# Y N M P L J H O F D
# FALSE TRUE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE
as.numeric(x = example_vec)
# [1] 0 1 0 0 1 1 1 1 1 1
example_vec + 0
# Y N M P L J H O F D
# 0 1 0 0 1 1 1 1 1 1
sapply(X = example_vec,FUN = as.numeric)
# Y N M P L J H O F D
# 0 1 0 0 1 1 1 1 1 1
【问题讨论】:
把class()
改成数字好像和改变存储模式效果一样。
相当丑陋,但你可以运行setNames(as.numeric(example_vec), names(example_vec))
我认为隐式或显式转换没有任何风险。如果您喜欢整数并输入更少的字符,请使用+example_vec
。另外,除非您考虑使用 setattr
或其他东西,否则我看不出有任何理由使用 data.table 进行标记。
啊,好的。我不认为这很困难。我没有 3.3.0,但 +example_vec
对我来说很好。
我同意@Frank。以某种方式通过setNames
重新应用名称感觉 最可靠,但我觉得example_vec + 0L
或+example_vec
的风险很低。
【参考方案1】:
一种可能性是使用mode<-
替换函数来更改对象的内部存储模式(类型)。此外,对于这种逻辑强制,整数比双精度数(即数字)更合适。
mode(example_vec) <- "integer"
example_vec
# Y N M P L J H O F D
# 0 1 0 0 1 1 1 1 1 1
来自help(mode)
-
mode(x) <- "newmode"
将对象x
的模式更改为newmode
。仅当存在适当的as.newmode
函数时才支持此功能,例如"logical"
、"integer"
、"double"
、"complex"
、"raw"
、"character"
、"list"
、"expression"
、@987654 @、"symbol"
和"function"
。 属性被保留。
文档还指出storage.mode<-
是mode<-
的更高效的原始版本。所以下面的也可以用。
storage.mode(example_vec) <- "integer"
但正如 @joran 在 cmets 中指出的那样,看起来 class<-
也做了同样的事情。
【讨论】:
【参考方案2】:只是抛出另一个选项,因为你的输入是一个逻辑向量,你可以使用ifelse()
。有人可能会说这种方法更加明确和直接:
ifelse(example_vec,1L,0L);
## Y N M P L J H O F D
## 0 1 0 0 1 1 1 1 1 1
基准测试
library(microbenchmark);
ifelse. <- function(x) ifelse(x,1L,0L);
sapply. <- function(x) sapply(x,as.integer);
setstoragemode <- function(x) storage.mode(x) <- 'integer'; x; ;
setmode <- function(x) mode(x) <- 'integer'; x; ;
setclass <- function(x) class(x) <- 'integer'; x; ;
as.and.setnames <- function(x) setNames(as.integer(x),names(x));
plus <- function(x) +x;
addzero <- function(x) x+0L;
## small scale (OP's example input)
set.seed(1045L);
x <- sample(c(T,F),10L,T);
names(x) <- sample(LETTERS,10L);
ex <- ifelse.(x);
identical(ex,sapply.(x));
## [1] TRUE
identical(ex,setstoragemode(x));
## [1] TRUE
identical(ex,setmode(x));
## [1] TRUE
identical(ex,setclass(x));
## [1] TRUE
identical(ex,as.and.setnames(x));
## [1] TRUE
identical(ex,plus(x));
## [1] TRUE
identical(ex,addzero(x));
## [1] TRUE
microbenchmark(ifelse.(x),sapply.(x),setstoragemode(x),setmode(x),setclass(x),as.and.setnames(x),plus(x),addzero(x));
## Unit: nanoseconds
## expr min lq mean median uq max neval
## ifelse.(x) 6843 8126.0 9627.13 8981 9837.0 21810 100
## sapply.(x) 18817 20100.5 23234.93 21383 22666.5 71418 100
## setstoragemode(x) 856 1283.0 1745.54 1284 1711.0 15396 100
## setmode(x) 7270 8126.0 9862.36 8982 10264.0 32074 100
## setclass(x) 429 1283.0 2138.97 1284 1712.0 32075 100
## as.and.setnames(x) 1283 1711.0 1997.78 1712 2139.0 7271 100
## plus(x) 0 428.0 492.39 428 428.5 9837 100
## addzero(x) 0 428.0 539.39 428 856.0 2566 100
## large scale
set.seed(1L);
N <- 1e5L;
x <- sample(c(T,F),N,T);
names(x) <- make.unique(rep_len(LETTERS,N));
ex <- ifelse.(x);
identical(ex,sapply.(x));
## [1] TRUE
identical(ex,setstoragemode(x));
## [1] TRUE
identical(ex,setmode(x));
## [1] TRUE
identical(ex,setclass(x));
## [1] TRUE
identical(ex,as.and.setnames(x));
## [1] TRUE
identical(ex,plus(x));
## [1] TRUE
identical(ex,addzero(x));
## [1] TRUE
microbenchmark(ifelse.(x),sapply.(x),setstoragemode(x),setmode(x),setclass(x),as.and.setnames(x),plus(x),addzero(x));
## Unit: microseconds
## expr min lq mean median uq max neval
## ifelse.(x) 7633.598 7757.1900 16615.71251 7897.4600 29401.112 96503.642 100
## sapply.(x) 86353.737 102576.0945 125547.32957 123909.1120 137900.406 264442.788 100
## setstoragemode(x) 84.676 92.8015 343.46124 98.3605 113.543 23939.133 100
## setmode(x) 124.020 155.0245 603.15744 167.2125 181.111 22395.736 100
## setclass(x) 85.104 92.3740 328.25393 100.2850 118.460 21807.713 100
## as.and.setnames(x) 70.991 78.2610 656.98177 82.3235 88.953 35710.697 100
## plus(x) 40.200 42.9795 48.68026 44.9040 49.608 88.953 100
## addzero(x) 181.326 186.4580 196.34882 189.6650 201.211 282.679 100
## very large scale
set.seed(1L);
N <- 1e7L;
x <- sample(c(T,F),N,T);
names(x) <- make.unique(rep_len(LETTERS,N));
ex <- ifelse.(x);
identical(ex,sapply.(x));
## [1] TRUE
identical(ex,setstoragemode(x));
## [1] TRUE
identical(ex,setmode(x));
## [1] TRUE
identical(ex,setclass(x));
## [1] TRUE
identical(ex,as.and.setnames(x));
## [1] TRUE
identical(ex,plus(x));
## [1] TRUE
identical(ex,addzero(x));
## [1] TRUE
microbenchmark(ifelse.(x),sapply.(x),setstoragemode(x),setmode(x),setclass(x),as.and.setnames(x),plus(x),addzero(x),times=5L);
## Unit: milliseconds
## expr min lq mean median uq max neval
## ifelse.(x) 1082.220903 1308.106967 3452.639836 1473.723533 6306.320235 7092.82754 5
## sapply.(x) 16766.199371 17431.458634 18401.672635 18398.345499 18843.890150 20568.46952 5
## setstoragemode(x) 13.298283 13.648103 173.574496 19.661753 24.736278 796.52806 5
## setmode(x) 19.043796 19.878573 75.669779 19.969235 39.683589 279.77370 5
## setclass(x) 14.025292 14.119804 259.627934 14.414457 26.838618 1228.74150 5
## as.and.setnames(x) 12.889875 24.241484 178.243948 24.962934 25.103631 804.02182 5
## plus(x) 7.577576 7.676364 9.047674 8.245142 8.253266 13.48602 5
## addzero(x) 18.861615 18.960403 71.284716 26.622226 26.950662 265.02867 5
看起来一元加号占了上风。 (而我的ifelse()
想法有点糟糕。)
【讨论】:
我很好奇为什么有些平均值远大于中位数。例如,在最后一个示例(“超大规模”)中,setstoragemode
和 setmode
具有基本相同的中位数(20 毫秒),但均值分别为 174 毫秒和 76 毫秒。对于setclass
,差距更大;平均值为 260 毫秒,而平均值仅为 14 毫秒。以上是关于将向量从二进制强制转换为“as.numeric”时保留名称?的主要内容,如果未能解决你的问题,请参考以下文章