【问题标题】:Change data.table column classes to integer64, double respectively将 data.table 列类分别更改为 integer64、double
【发布时间】:2018-12-14 22:20:20
【问题描述】:

给定 data.table dt:

dt <- structure(list(V1 = c("1544018118438041139", "1544018118466235879", 
"1544018118586849680", "1544018118601169211", "1544018118612947335", 
"1544018118614422179"), V2 = c("162", "162", "161.05167", "158.01309", 
"157", "157"), V3 = c("38", "38", "36.051697", "33.01306", "32", 
"32"), V4 = c("0.023529414", "0.025490198", "0.023529414", "0.027450982", 
"0.03137255", "0.03137255"), V5 = c("1", "1", "1", "1", "1", 
"1"), V6 = c("2131230815", "2131230815", "2131230815", "2131230815", 
"2131230815", "2131230815"), V7 = c("1", "0", "0", "0", "0", 
"-1")), class = c("data.table", "data.frame"), row.names = c(NA, 
-6L), .internal.selfref = <pointer: 0x2715f60>)

我希望第一列为bit64::as.integer64(),其余列为as.numeric()

我正在尝试这样做:

dt <- dt[ ,V1 := bit64::as.integer64(V1)]

dt[, lapply(.SD, as.numeric), .SDcols = -c("V1")]

但它似乎没有做我想做的事,请告知如何将特定列更改为 A 类(integer64),将其余列更改为另一个 B 类(比如as.numeric())?

【问题讨论】:

  • 但我希望它是第一列和其余列,我不能保证我会始终获得这些列名,我希望它是通用的。 @markus
  • 再次@markus 第一列不是“V1”
  • .SDcols = setdiff(names(dt), names(dt)[1])
  • 你需要做dt &lt;- dt[, lapply(...],但不是在第一种情况下,因为:=你通过引用更改V1列。

标签: r data.table


【解决方案1】:

从上面的 cmets 看来,您似乎希望能够一步完成这一切,而不是将第一个转换为 integer64,然后将其余的转换为 double。一种方法是:

dt[, names(dt) := Map(function(fun, x) fun(x), rep(list(bit64::as.integer64, as.numeric), times = c(1,length(.SD) - 1)), .SD), .SDcols = names(dt)]

Map 函数会一起遍历您的输入。也就是说,它获取第一个和第二个向量的第一个元素并将它们作为参数传递给我们的函数。然后它获取两个向量的第二个元素并将它们传递给函数。

在我们的Map 电话中,我们有:

  • 要应用的主要功能。这是一个匿名函数,它接受两个参数 (1) fun 和 (2) x。我们函数的结果是将fun 应用到xfun(x) 的结果。举个具体的例子试试:

    myfun <- function(fun, x){
      fun(x)
    }
    res<-myfun(as.numeric, c("1","1")); class(res)
    
  • 要传递给我们的主函数的函数列表。这些将在我们的主函数中用作fun。在这种情况下,它的list(as.integer64, as.numeric, as.numeric,...)

  • 要传递给我们的主函数的向量列表。这些将在我们的主函数中用作x。在这种情况下,我们dt 的每一列。

这是如何工作的快速而肮脏的视觉帮助(假设 custom_function 有两个参数):

【讨论】:

  • @steves 如果不清楚,请告诉我。我想我可能会添加一个关于Map 的图形
  • 超级清晰!!!你肯定解决了我遇到的这类问题,但对我来说最大的问题仍然是处理这些大的 19 位时间戳数字。我几乎尝试了任何方法,但没有什么能帮助我在不丢失精度的情况下处理这些大数字。也许我可以以某种方式向您展示我的问题,也许您已经看到了相同的问题。
  • @steves 很抱歉,如果没有看到细节,很难说。作为一个新问题,这可能会更好。此外,我没有太多存储大量数字的经验。也许考虑记录日志或进行一些转换?
  • 这些是纳秒时间戳。所有转换,包括转换为双重、松散的信息。
  • @DirkEddelbuettel 请看看我的回答,我设法解决了。
【解决方案2】:

在我看来,您有一个 data.table 对象,自纪元以来的时间戳为 integer64 纳秒。我在工作中使用它来表示高分辨率时间戳。

好消息是 data.table 支持这一点——通过依赖我们的包nanotime,它本身使用bit64 作为integer64 类型。但是,我创建时间戳的方式不同,通常是从我检索数据的编译代码中创建的。

我在this post 中的Rcpp Gallery 对此进行了详细描述。所以一些好消息:这是可以做到的。一些坏消息:我不认为你可以按照你想要的方式去做,因为我们只能通过double,它只有 16 位小数精度,而不是 19 位。但也许我缺少技巧,所以如果存在更简单的解决方案我' d 全力以赴。 (而且我一直忘记是否有“从字符串方法解析 int64”。我从来没有走那条路,因为你不能大规模地这样做——我也处理相当大的数据集。)

【讨论】:

  • 我设法做到了,请看我的回答。 @dirk_eddelbuettel
【解决方案3】:

谢谢大家,@dirk_eddelbuettel 我设法做到了:

1) 加载所有JSON 文件(在我的情况下)并使用

bigint_as_char=TRUE

fromJSON 命令内。

2) 现在你有一个大表,所有列都是字符。

3) 将时间戳列转换为bit64::as.integer64() - 你会得到我想要的数字。

4) 将其余的转换为所需的类型。

5) 当我想执行计算时,例如timestamp - lag(timestamp),我将lag_timestamp = lag(timestamp)(带有dplyr::mutate)添加为新列并添加diff_column = 存储它as.character()

6) 您几乎完成了 - 新的 diff 列将我想要的值存储为字符串/字符,现在您可以在需要时将其转换为 as.numeric() 或应用 ifelse() 来处理不相关的值。

7) 仅此而已,它非常适合我,并且不会使 R Studio 崩溃。

在应用我的解决方案之前,R Studio 崩溃了。

【讨论】:

  • JSON? 颤抖 Textconversion 很慢,本质上你的答案和我的一样,因为你不得不求助于帮助程序包。
  • 只是一个小宣传,我是一名数据科学家,使用 AWS S3 中的文件进行首次研究。之后我不需要处理它,因为 ETL 专业人员为我提供了关系数据库,其中包含我需要的所有列。我只是连接到它并跳过数据准备阶段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-08
  • 2012-05-06
  • 2015-05-08
  • 1970-01-01
  • 2013-01-16
  • 2013-10-27
  • 2015-11-23
相关资源
最近更新 更多