问题:
我在 R 中工作。我希望 2 个 data.tables 的共享列(共享意味着相同的列名)具有匹配的类。我正在努力寻找一种将未知类的对象一般转换为另一个对象的未知类的方法。
更多上下文:
我知道如何在 data.table 中设置列的类,并且我知道 as
功能。另外,这个问题不完全是 data.table
具体的,但当我使用 data.table
时经常出现s。此外,假设所需的强制是可能的。
我有 2 个数据表。它们共享一些列名称,而这些列旨在表示相同的信息。对于表 A 和表 B 共享的列名,我希望 A 的类与 B 中的类(或其他方式)相匹配。
示例 data.table
s:
A <- structure(list(year = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), stratum = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L)), .Names = c("year", "stratum"), row.names = c(NA, -45L), class = c("data.table", "data.frame"))
B <- structure(list(year = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), stratum = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L), bt = c(-9.95187702337873, -9.48946944434626, -9.74178662514147, -5.36167545158338, -4.76405522202426, -5.41964239804882, -0.0807951335119085, 0.520481719699774, 0.0393874225863578, 5.40557402913123, 5.47927931969583, 5.37228402911139, 9.82774396910091, 9.89629694010177, 9.98105260936272, -9.82469892896284, -9.42530210357904, -9.66171049964775, -5.17540952901709, -4.81859082470115, -5.3577146169737, -0.0685310909609001, 0.441383303157166, -0.0105897444321987, 5.24205882775199, 5.65773605162835, 5.40217185632441, 9.90299445851434, 9.78883672575814, 9.98747998379124, -9.69843398105195, -9.31530717395811, -9.77406601252698, -4.83080164375344, -4.89056304189872, -5.3904000267275, -0.121508487954861, 0.493798577602088, -0.118550709142654, 5.23654772583187, 5.87760447006892, 5.22478092346285, 9.90949768116403, 9.85433376398086, 9.91619307289277), yr = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3)), .Names = c("year", "stratum", "bt", "yr"), row.names = c(NA, -45L), class = c("data.table", "data.frame"), sorted = c("year", "stratum"))
这是它们的样子:
> A
year stratum
1: 1 1
2: 1 2
3: 1 3
4: 1 4
> B
year stratum bt yr
1: 1 1 -9.95187702 1
2: 1 2 -9.48946944 1
3: 1 3 -9.74178663 1
4: 1 4 -5.36167545 1
以下是类(class):
> sapply(A, class)
year stratum
"integer" "integer"
> sapply(B, class)
year stratum bt yr
"numeric" "integer" "numeric" "numeric"
手动,我可以通过以下方式完成所需的任务:
A[,year:=as.numeric(year)]
当只有 1 列要更改时,这很容易,您提前知道该列,并且提前知道所需的类。如果需要,将任意列转换为给定类也很容易。我也知道如何将任意列转换为任何给定的类。
我的尝试失败:
(编辑:这确实有效;请参阅我的答案)
s2c <- function (x, type = "list")
{
as.call(lapply(c(type, x), as.symbol))
}
# In this case, I can assume all columns of A can be found in B
# I am also able to assume that the desired conversion is possible
B.class <- sapply(B[,eval(s2c(names(A)))], class)
for(col in names(A)){
set(A, j=col, value=as(A[[col]], B.class[col]))
}
但这仍然将年份列返回为
"integer"
,不是 "numeric"
:> sapply(A, class)
year stratum
"integer" "integer"
上面例子中的问题是
class(as(1L, "numeric"))
仍然返回 "integer"
.另一方面,class(as.numeric(1L))
返回 "numeric"
;但是,我不知道需要提前as.numeric
需要。问题,重述:
当列和
to
都不匹配时,如何使列类匹配/from
类(class)是提前知道的?其他想法:
在某种程度上,问题主要是关于任意类匹配。我经常在使用 data.table 时遇到这个问题,因为它非常关注类匹配。例如,我在需要插入
NA
时遇到了类似的问题适当的类型( NA_real_
与 NA_character_
等),具体取决于列的类别(请参阅 This Question 中的相关问题/问题)。同样,这个问题可以被看作是在事先不知道的任意类之间转换的一般问题。过去,我使用
switch
编写函数做类似 switch(class(x), double = as.numeric(...), character = as.character(...), ...
的事情,但这似乎是一个大丑陋。我在 data.table 的上下文中提出这个的唯一原因是因为它是我最经常遇到对此类功能的需求的地方。
最佳答案
不是很优雅,但您可以“构建”as.*
像这样调用:
for (x in colnames(A)) { A[,x] <- eval( call( paste0("as.", class(B[,x])), A[,x]) )}
关于r - 将任意类的列转换为另一个 data.table 中匹配列的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34091811/