从命名向量列表中有效地创建矩阵

时间:2018-01-22 12:19:24

标签: r

我想从带有名字的矢量创建一个矩阵。其中列名是元素的名称,如果某些名称不在向量中,则对应的元素将为NA(或0)。

一个简单的例子是这样的:

set.seed(1)
vec_a <- rnorm(10)
names(vec_a) <- sample(letters, 10)
vec_b <- rnorm(10)
names(vec_b) <- sample(letters, 10)
vec_c <- rnorm(10)
names(vec_c) <- sample(letters, 10)
vec_d <- rnorm(10)
names(vec_d) <- sample(letters, 10)

example_matrix <- bind_rows(vec_a, vec_b, vec_c, vec_d) 

example_matrix

## # A tibble: 4 x 24
##            y         f          p          c          z          i         a           h
##        <dbl>     <dbl>      <dbl>      <dbl>      <dbl>      <dbl>     <dbl>       <dbl>
## 1 -0.6264538 0.1836433 -0.8356286  1.5952808  0.3295078 -0.8204684 0.4874291  0.73832471
## 2         NA 0.8212212         NA  0.9189774         NA         NA        NA          NA
## 3         NA        NA         NA -0.0593134         NA         NA        NA -0.05380504
## 4         NA        NA         NA         NA -0.7074952  0.7685329 0.3981059          NA
## # ... with 16 more variables: x <dbl>, v <dbl>, m <dbl>, k <dbl>, b <dbl>, g <dbl>, j <dbl>,
## #   l <dbl>, t <dbl>, r <dbl>, q <dbl>, e <dbl>, o <dbl>, u <dbl>, s <dbl>, d <dbl>

我知道bind_rows()有效,example_matrix是我想要的。

问题是如果向量变大,这个过程可能会很慢。

再举一个例子:

all_names <- do.call(paste0, replicate(5, sample(LETTERS, 1e4, TRUE), FALSE))
n <- 5e3
vec_a <- rnorm(n)
names(vec_a) <- sample(all_names, n)
vec_b <- rnorm(n)
names(vec_b) <- sample(all_names, n)

tmp <- bind_rows(vec_a, vec_b) # works, but slow

这已经很慢了,我的数据比这大(50K唯一名称,每个向量有10K-30K元素)。

我想创建名称的整数索引并构造一个直接赋值(i,j,x)的稀疏矩阵,但不确定构造这些索引的最简单方法是什么。

所以问题是什么是快速创建这个矩阵的方法?欢迎提出任何建议。

1 个答案:

答案 0 :(得分:2)

您可以尝试使用rbindlist包中的data.table功能。参见示例。

require(data.table)
require(dplyr)

all_names <- unique(do.call(paste0, replicate(5, sample(LETTERS, 1e4, TRUE), FALSE)))
anyDuplicated(all_names)
n <- 5e3

vec_a <- rnorm(n)
names(vec_a) <- sample(all_names, n)

vec_b <- rnorm(n)
names(vec_b) <- sample(all_names, n)

length(union(names(vec_a), names(vec_b)))

system.time(tmp1 <- bind_rows(vec_a, vec_b))

system.time(tmp2 <- rbindlist(list(as.list(vec_a), as.list(vec_b)), fill = T))

all.equal(tmp1, tmp2)

输出:

> system.time(tmp1 <- bind_rows(vec_a, vec_b))
   user  system elapsed 
   3.20    0.00    3.21 

> system.time(tmp2 <- rbindlist(list(as.list(vec_a), as.list(vec_b)), fill = T))
   user  system elapsed 
   0.01    0.00    0.01 

> all.equal(tmp1, tmp2)
[1] TRUE