data.table 更新另一个 table 的因子水平

Updating factor levels from another table by data.table

我想从另一个table更新table的非数字列的因子水平,

这是我试过的;

set.seed(1453)

library(data.table)

bigger_table <- data.table(region = paste0(rep('region_',50),sample(1:4,50,replace=T)),
                           factor_column = factor(sample(LETTERS[1:3],50,replace=T)),
                           numeric_column = rnorm(50,20,2))
                           
subset_table <- bigger_table[region=='region_1']

nonnumeric_column <- names(bigger_table)[sapply(bigger_table,function(x) !is.numeric(x))]
                                                
subset_table[,(nonnumeric_column) := lapply(.SD,function(x) factor(x,levels = unique(bigger_table[,x]))),.SDcols=nonnumeric_column]

但它无法正常工作并出现错误。

在我想要的输出中;在子集 table 中,region 列应该是因子并且具有从 bigger_table.

提前致谢。

不会考虑级别不提供简单的解决方案吗?

subset_table$region <- factor(subset_table$region, levels = unique(bigger_table$region))

如果问题出在多列上,那么 dplyr 解决方案是:

library(dplyr)

subset_table <- subset_table |>
  mutate(across(all_of(nonnumeric_column), ~ factor(.x, levels = unique(bigger_table$region))))

请注意,您的 nonnumeric_column 包括“factor_column”,它没有映射到区域,因此更改为所有 <NA>

在您的 MWE 中,最简单的解决方案是在较大的 table 中创建一个因子,然后在数据的每个子集中保留因子水平。

# Easiest solution: Create a factor in the original table and the subset retains the levels
library(data.table)
set.seed(1453)
bigger_table <- data.table(region = factor(paste0(rep('region_',50),sample(1:4,50,replace=T))),
                           factor_column = factor(sample(LETTERS[1:3],50,replace=T)),
                           numeric_column = rnorm(50,20,2))

subset_table <- bigger_table[region=='region_1']
subset_table$region
#>  [1] region_1 region_1 region_1 region_1 region_1 region_1 region_1 region_1
#>  [9] region_1 region_1 region_1 region_1 region_1 region_1 region_1
#> Levels: region_1 region_2 region_3 region_4

reprex package (v2.0.1)

于 2021-11-11 创建

如果您必须使用另一个 table 来更新它们,那么您可以使用以下代码。在你的例子中,有一个错误,因为在 unique(bigger_table[,x]) 中,x 不是列名,而是该列的内容。

# Update a table with the factor levels of another table
library(data.table)
set.seed(1453)
bigger_table <- data.table(region = paste0(rep('region_',50),sample(1:4,50,replace=T)),
                           factor_column = factor(sample(LETTERS[1:3],50,replace=T)),
                           numeric_column = rnorm(50,20,2))

subset_table <- bigger_table[region=='region_1']
nonnumeric_column <- names(bigger_table)[sapply(bigger_table,function(x) !is.numeric(x))]

for(col in nonnumeric_column) {
  set(subset_table, j = col, value = factor(subset_table[, get(col)], levels = bigger_table[, unique(get(col))]))
}

subset_table$region
#>  [1] region_1 region_1 region_1 region_1 region_1 region_1 region_1 region_1
#>  [9] region_1 region_1 region_1 region_1 region_1 region_1 region_1
#> Levels: region_1 region_3 region_2 region_4

reprex package (v2.0.1)

于 2021-11-11 创建

您可以执行以下操作:

subset_table[, 
  (nonnumeric_column) := 
    lapply(nonnumeric_column, \(x) factor(get(x), levels = unique(bigger_table[[x]])))
]

导致

> lapply(subset_table, levels)
$region
[1] "region_1" "region_3" "region_2" "region_4"

$factor_column
[1] "C" "B" "A"

$numeric_column
NULL

您原来的解决方案中的问题是 x 没有返回列的名称,而是返回实际的列。您可以通过以下方式查看:

subset_table[, lapply(.SD, \(x) print(x)), .SDcols=nonnumeric_column]