【问题标题】:Can data.table assign-by-reference (mutate) preserve vector namesdata.table 可以通过引用分配(变异)保留向量名称吗
【发布时间】:2021-12-28 22:42:41
【问题描述】:

我有一个命名的颜色向量,我用它来分配给一个使用:= 的新列,基于列值。如果我使用 dplyr 变异,结果与 data.table 样式变异不同。使用 dplyr,向量名称被保留,而在 data.table 中,名称会丢失。

让我带你了解一下我到目前为止所了解的内容。

# first I make a named vector of colors
movieColors <- c("Aladdin" = "steelblue1",
                 "Beauty" = "gold1",
                 "Brave" = "darkorange1")
# lets create some dummy data
dt <- data.table::data.table(movie = c("Aladdin", "Beauty", "Brave"), 
                             movieNum = 1:3)

# I want a new column that tells me the color of each movie for each row
# a dplyr mutate
dt1 <- dplyr::mutate(.data = dt, 
                     movColor = movieColors[movie])
# a data.table mutate
dt2 <- dt[, movColor := movieColors[movie]]

# check the results and they look the same
dt1
dt2

# check that they are the same
dplyr::all_equal(dt1, dt2)
# they're not the same?

# the dplyr mutate is preserving the named vector
dt1$movColor
# the data.table mutate does not preserve the named vector
dt2$movColor

如果你运行它,你可以看到dt1,dplyr 版本,打印:

Aladdin            Beauty         Brave 
"steelblue1"       "gold1"        "darkorange1" 

当 data.table 版本时,dt2 打印:

[1] "steelblue1"   "gold1"        "darkorange1"

为什么 data.table 不保留命名向量?有没有办法强制它这样做?

【问题讨论】:

  • 这似乎是一个 XY 问题。不会丢失信息,因为名称在单独的列中可用 (movie)。任何后续的子集、排序或分组操作都将通过使用带有名称的列而不是名称属性以更 data.table 的方式完成。有关名称列不存在的情况,另请参阅 here
  • 谢谢。我有一个构造不佳的 ggplot 链,我试图在其中自我引用 scale_fill_manual。当我意识到我遇到了什么问题时,我找到了一个更好的方法,但仍然想知道为什么构造不佳的版本只能与 dplyr 一起使用。

标签: r dplyr data.table


【解决方案1】:

正如@dww 指出的那样,没有特别需要将名称保留在电影列中。虽然我不知道为什么 {dplyr} 支持而 {data.table} 不支持,但您可以使用 data.table::setattr() 来获得相同的结果。

# first I make a named vector of colors
movieColors <- c("Aladdin" = "steelblue1",
                 "Beauty" = "gold1",
                 "Brave" = "darkorange1")
# lets create some dummy data
dt <- data.table::data.table(movie = c("Aladdin", "Beauty", "Brave"), 
                             movieNum = 1:3)

# I want a new column that tells me the color of each movie for each row
# a dplyr mutate
dt1 <- dplyr::mutate(.data = dt, 
                     movColor = movieColors[movie])
#> Registered S3 methods overwritten by 'tibble':
#>   method     from  
#>   format.tbl pillar
#>   print.tbl  pillar
# a data.table mutate
dt2 <- dt[, movColor := movieColors[movie]]



# size prior to adding names
object.size(dt2)
#> 2008 bytes

# add names to the movies column in place
data.table::setattr(dt2$movColor, "names", dt2$movie)

#size after adding names
object.size(dt2)
#> 2368 bytes



# check the results and they look the same
dt1
#>      movie movieNum    movColor
#> 1: Aladdin        1  steelblue1
#> 2:  Beauty        2       gold1
#> 3:   Brave        3 darkorange1
dt2
#>      movie movieNum    movColor
#> 1: Aladdin        1  steelblue1
#> 2:  Beauty        2       gold1
#> 3:   Brave        3 darkorange1

# check that they are the same
dplyr::all_equal(dt1, dt2)
#> [1] TRUE

# the dplyr mutate is preserving the named vector
dt1$movColor
#>       Aladdin        Beauty         Brave 
#>  "steelblue1"       "gold1" "darkorange1"
# the data.table mutate does now preserve the named vector
dt2$movColor
#>       Aladdin        Beauty         Brave 
#>  "steelblue1"       "gold1" "darkorange1"

如您所见,我只是使用 data.table 中已有的信息。因此,对象的大小增加。可能这也是为什么 data.table 会自动剥离 names 的答案。

【讨论】:

  • 谢谢。我有一个构造不佳的 ggplot 链,我试图在其中自我引用 scale_fill_manual。当我意识到我遇到了什么问题时,我找到了一个更好的方法,但仍然想知道为什么构造不佳的版本只能与 dplyr 一起使用。
猜你喜欢
  • 2013-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-03
  • 1970-01-01
相关资源
最近更新 更多