R语言 使用apply(. SD,1,FUN)的数据表输出不一致

5f0d552i  于 2023-06-19  发布在  其他
关注(0)|答案(5)|浏览(140)

在R中使用data.table,我尝试连接两个列并创建一个新列,其中我具有上一步的唯一值。在下面的例子中,你可以看到代码在帧z1上工作正常,但是在帧z2上我得到了一个错误。但是,这两个表的创建方式相同。这两列有不同的信息,但这不应该成为相同代码在z2上不起作用的原因。
非常感谢你的帮助,如果我不清楚,请告诉我。
最好

library(data.table)

z1 <- data.table(a = c("ARE_2014_HIES_D1_INC_GROUP", "ARE_2014_HIES_D1_INC_GROUP"), 
                 b = c("ARE_2014_HIES_D1_INC_GROUP", "ARE_2015_HIES_D1_INC_GROUP"))

z2 <- data.table(a = c("ARG_1980_EPH_D2_INC_GROUP", "ARG_1980_EPH_D2_INC_GROUP"), 
                 b = c("ARG_1986_EPH_D2_INC_HIST", "ARG_1986_EPH_D2_INC_HIST"))

z1[,
   cache_id := as.list(apply(.SD, 1, unique)),
   .SDcols = c("a", "b")
]

z1[]
#>                             a                          b
#> 1: ARE_2014_HIES_D1_INC_GROUP ARE_2014_HIES_D1_INC_GROUP
#> 2: ARE_2014_HIES_D1_INC_GROUP ARE_2015_HIES_D1_INC_GROUP
#>                                                 cache_id
#> 1:                            ARE_2014_HIES_D1_INC_GROUP
#> 2: ARE_2014_HIES_D1_INC_GROUP,ARE_2015_HIES_D1_INC_GROUP

z2[,
   cache_id := as.list(apply(.SD, 1, unique)),
   .SDcols = c("a", "b")
]
#> Error in `[.data.table`(z2, , `:=`(cache_id, as.list(apply(.SD, 1, unique))), : Supplied 4 items to be assigned to 2 items of column 'cache_id'. If you wish to 'recycle' the RHS please use rep() to make this intent clear to readers of your code.
z2[]
#>                            a                        b
#> 1: ARG_1980_EPH_D2_INC_GROUP ARG_1986_EPH_D2_INC_HIST
#> 2: ARG_1980_EPH_D2_INC_GROUP ARG_1986_EPH_D2_INC_HIST

创建于2023-06-12带有reprex v2.0.2

nnsrf1az

nnsrf1az1#

目前还不清楚你为什么要这样做,我怀疑我们正在处理一个xy problem在这里。无论如何,您应该几乎永远不需要迭代data.table的行。这通常是一个设计问题。如果你真的需要这样做,那么如果它不是一次性的,或者你的data.table实际上很大,那么就转向Rcpp。
无论如何,在特定的示例中,您可以使用data.table::unique

library(data.table)
z1 <- data.table(a = c("ARE_2014_HIES_D1_INC_GROUP", "ARE_2014_HIES_D1_INC_GROUP"), 
                b = c("ARE_2014_HIES_D1_INC_GROUP", "ARE_2015_HIES_D1_INC_GROUP"))
z1[, rn := .I]
unique(melt(z1, "rn"), by = c("rn", "value"))
#   rn variable                      value
#1:  1        a ARE_2014_HIES_D1_INC_GROUP
#2:  2        a ARE_2014_HIES_D1_INC_GROUP
#3:  2        b ARE_2015_HIES_D1_INC_GROUP

如果必须这样做,可以将value列拆分为rn列,并将其添加到data.table中。但是,你为什么需要这个?

quhf5bfb

quhf5bfb2#

apply如果每个结果的长度相同则返回矩阵,否则列出:

apply(z1[,.(a ,b)], 1, unique)

[[1]]
[1] "ARE_2014_HIES_D1_INC_GROUP"

[[2]]
[1] "ARE_2014_HIES_D1_INC_GROUP" "ARE_2015_HIES_D1_INC_GROUP"

apply(z2[, .(a, b), 1, unique)

     [,1]                        [,2]                       
[1,] "ARG_1980_EPH_D2_INC_GROUP" "ARG_1980_EPH_D2_INC_GROUP"
[2,] "ARG_1986_EPH_D2_INC_HIST"  "ARG_1986_EPH_D2_INC_HIST"

此外,矩阵上的as.list不会给予你列列表,但你会得到每个元素作为列表的元素:

as.list(apply(z2[, .(a, b)], 1, unique))

[[1]]
[1] "ARG_1980_EPH_D2_INC_GROUP"

[[2]]
[1] "ARG_1986_EPH_D2_INC_HIST"

[[3]]
[1] "ARG_1980_EPH_D2_INC_GROUP"

[[4]]
[1] "ARG_1986_EPH_D2_INC_HIST"

因此,警告的长度。
我不太清楚你的最终结果应该是什么,所以我不能提供明确的答案。

vsikbqxv

vsikbqxv3#

您可以尝试以下方法:

z1[, cache_id:=list(.(unique(c(a,b)))), 1:nrow(z1)]

对于z2也是如此
输出:

a                          b                                              cache_id
                       <char>                     <char>                                                <list>
1: ARE_2014_HIES_D1_INC_GROUP ARE_2014_HIES_D1_INC_GROUP                            ARE_2014_HIES_D1_INC_GROUP
2: ARE_2014_HIES_D1_INC_GROUP ARE_2015_HIES_D1_INC_GROUP ARE_2014_HIES_D1_INC_GROUP,ARE_2015_HIES_D1_INC_GROUP
zsbz8rwp

zsbz8rwp4#

另一种方法不需要像@langtang的回答那样遍历行:

z1[, cache_id := lapply(.mapply(c, .SD, NULL), unique), .SDcols = c("a", "b")
   ][, cache_id := sapply(cache_id, paste, collapse = ", ")]
yeotifhr

yeotifhr5#

谢谢大家的回答。他们真的帮助了我,我学到了更多关于apply和data.table的知识。我选择@Langtang回答,因为它是最快的。然而,Thak you so much@hieu-nguyen for both solutions.我认为simply = FALSE是问题的关键,但你在评论中提出了这一点,我不能选择作为答案。请在基准以下查找

library(data.table)

n <- 1e4
x <- sapply(1:n, \(x) sample(letters, 10) |> paste(collapse = ""))
y <- sapply(1:n, \(x) sample(letters, 10) |> paste(collapse = ""))

ni <- sample(1:n, floor(n/10), replace = FALSE)

x[ni] <- y[ni]


z1 <- data.table(a = x, 
                 b = y)

bench <- microbenchmark::microbenchmark(
  times = 30,
  simplify = z1[,
                cache_id := as.list(apply(.SD, 1, unique, simplify = FALSE)),
                .SDcols = c("a", "b")],
  loop_rows = z1[, cache_id:=list(.(unique(c(a,b)))), 1:nrow(z1)], 
  mapply    = z1[, cache_id := lapply(.mapply(c, .SD, NULL), unique), .SDcols = c("a", "b")]
)

bench
#> Unit: milliseconds
#>       expr       min        lq     mean   median       uq      max neval cld
#>   simplify 145.03549 171.67624 209.7165 214.4948 244.1717 268.3255    30 a  
#>  loop_rows  80.62317  98.74864 110.2403 106.6774 122.0016 148.4702    30  b 
#>     mapply 337.39212 409.21162 482.0041 478.9344 544.5397 765.9302    30   c

创建于2023 - 06 - 13带有reprex v2.0.2

相关问题