将向量的每个元素添加为 data.table 中的新列

Add each element of a vector as new column in data.table

如果一个向量有 5 个元素,我需要向 data.table 添加 5 列。 我的第一个新列的唯一值是我的向量的元素 1。

这是我可以用 for 做的事情,如下面的代表 :

foo <- data.table(col1 = 1:10, col2 = sample(letters[1:5], replace = TRUE))

fun.add <- function(DT) {
  
  v1 <- c(3, 5.5, 9)
  v2 <- c("x", "y", "z")
  
  for (j in 1:3) {
    DT[, paste0("aaa", j) := v1[j]]
    DT[, paste0("bbb", j) := v2[j]]
  }
  
  # DT[, paste0("aaa", 1:3),  := ...]
}

fun.add(foo)

我宁愿在没有 for 的情况下这样做,而是喜欢在评论行中。 在这种情况下,我不能使用 lapply.SD ... 有办法吗?另一种方式?

谢谢!!

这是我的解决方案。

输入:

v1  <- c(3, 5.5, 9)
v2  <- c("x", "y", "z")
foo <- data.table(col1 = 1:10, col2 = sample(letters[1:5], replace = TRUE))

N_col0 <- NCOL(foo) # used later on to redefine column class

代码:

v12 <- c(rbind(v1, v2))
m12 <- matrix(rep(v12, each = NROW(foo)), NROW(foo))
foo <- cbind(foo, m12)
numeric_col <- grep("[0-9]", v12) + N_col0
for(j in numer_col){set(foo, j=j, value=as.numeric(foo[[j]]))}

代码解释:

1.Combine v1 & v2.

v12 <- c(rbind(v1, v2)) # note it is a character vector

print(v12)
[1] "3"   "x"   "5.5" "y"   "9"   "z"  

2.Create一个v12的字符矩阵。如果您愿意,您可以在此阶段设置列名。

m12 <- matrix(rep(v12, each = NROW(foo)), NROW(foo))

print(v12)
      [,1] [,2] [,3]  [,4] [,5] [,6]
 [1,] "3"  "x"  "5.5" "y"  "9"  "z" 
 [2,] "3"  "x"  "5.5" "y"  "9"  "z" 
 [3,] "3"  "x"  "5.5" "y"  "9"  "z" 
 [4,] "3"  "x"  "5.5" "y"  "9"  "z" 
 [5,] "3"  "x"  "5.5" "y"  "9"  "z" 
 [6,] "3"  "x"  "5.5" "y"  "9"  "z" 
 [7,] "3"  "x"  "5.5" "y"  "9"  "z" 
 [8,] "3"  "x"  "5.5" "y"  "9"  "z" 
 [9,] "3"  "x"  "5.5" "y"  "9"  "z" 
[10,] "3"  "x"  "5.5" "y"  "9"  "z" 

3.cBind foo & m12.

foo<- cbind(foo, m12)

print(foo)
    col1 col2 V1 V2  V3 V4 V5 V6
 1:    1    b  3  x 5.5  y  9  z
 2:    2    d  3  x 5.5  y  9  z
 3:    3    d  3  x 5.5  y  9  z
 4:    4    e  3  x 5.5  y  9  z
 5:    5    d  3  x 5.5  y  9  z
 6:    6    b  3  x 5.5  y  9  z
 7:    7    d  3  x 5.5  y  9  z
 8:    8    d  3  x 5.5  y  9  z
 9:    9    e  3  x 5.5  y  9  z
10:   10    d  3  x 5.5  y  9  z

4.All 新列是字符列。为了解决这个问题,我们可以检测向量 12 中的哪些元素是数字,并使用数据函数集 table.

foo[, lapply(.SD, class)]

      col1      col2        V1        V2        V3        V4        V5        V6
1: integer character character character character character character character


numeric_col <- grep("[0-9]", v12) + N_col0
for(j in numer_col){set(foo, j=j, value=as.numeric(foo[[j]]))}

foo[, lapply(.SD, class)]

  col1      col2      V1        V2      V3        V4      V5        V6
1: integer character numeric character numeric character numeric character

我们可以更有效地执行此操作,而不是在 for 循环中执行此操作,即将向量转换为具有 as.listlist 并通过分配创建列(:=) 到使用 paste 创建的列名向量(paste 被向量化)

foo[, paste0("aaa", seq_along(v1)) := as.list(v1)]
foo[, paste0("bbb", seq_along(v2)) := as.list(v2)]

如果我们将它包装在一个函数中

fun.add <- function(DT) {
     v1 <- c(3, 5.5, 9)
     v2 <- c("x", "y", "z")
     DT[, paste0("aaa", seq_along(v1)) := as.list(v1)]
     DT[, paste0("bbb", seq_along(v2)) := as.list(v2)][]
    return(DT)
}

-测试

> fun.add(foo)
    col1 col2 aaa1 aaa2 aaa3 bbb1 bbb2 bbb3
 1:    1    a    3  5.5    9    x    y    z
 2:    2    e    3  5.5    9    x    y    z
 3:    3    d    3  5.5    9    x    y    z
 4:    4    c    3  5.5    9    x    y    z
 5:    5    b    3  5.5    9    x    y    z
 6:    6    a    3  5.5    9    x    y    z
 7:    7    e    3  5.5    9    x    y    z
 8:    8    d    3  5.5    9    x    y    z
 9:    9    c    3  5.5    9    x    y    z
10:   10    b    3  5.5    9    x    y    z