繁体   English   中英

data.table:用函数逐行转换列的子集

[英]data.table: transforming subset of columns with a function, row by row

拥有一个主要为数值的 data.table 怎么能只转换列的子集并将它们放回原始数据表? 通常,我不想将任何汇总统计信息添加为单独的列,只需交换转换后的统计信息即可。

假设我们有一个 DT。 它有 1 列名称和 10 列数值。 我有兴趣为该数据表的每一行使用基数 R 的“缩放”函数,但仅适用于这 10 个数字列。

并对此进行扩展。 如果我有一个包含更多列的数据表并且我需要使用列名来告诉 scale 函数在哪些数据点上应用该函数,该怎么办?

使用常规 data.frame 我会这样做:

df[,grep("keyword",colnames(df))] <- t(apply(df[,grep("keyword",colnames(df))],1,scale))

我知道这看起来很麻烦,但总是对我有用。 但是,我无法在 data.tables 中找到一种简单的方法。

我想像这样的东西为 data.tables 工作:

dt[,grep("keyword",colnames(dt)) := scale(grep("keyword",colnames(dt)),center=F)]

但事实并非如此。

编辑:

使用按行缩放的版本更新列的另一个示例:

dt = data.table 对象

dt[,grep("keyword",colnames(dt),value=T) := as.data.table(t(apply(dt[,grep("keyword",colnames(dt)),with=F],1,scale)))]

太糟糕了,它需要内部的“as.data.table”部分,因为来自 apply 函数的转置值是一个矩阵。 也许 data.table 应该在更新列时自动将矩阵强制转换为 data.tables?

如果您确实需要按行缩放,您可以尝试分两步进行:

# compute mean/sd:
mean_sd <- DT[, .(mean(unlist(.SD)), sd(unlist(.SD))), by=1:nrow(DT), .SDcols=grep("keyword",colnames(DT))]

# scale
DT[, grep("keyword",colnames(DT), value=TRUE) := lapply(.SD, function(x) (x-mean_sd$V1)/mean_sd$V2), .SDcols=grep("keyword",colnames(DT))]

第 1 部分:您要求的单行解决方案

# First lets take a look at the data in the columns:
DT[,.SD, .SDcols = grep("corrupt", colnames(DT))]`

单行解决方案版本 1:使用 magrittR 和管道运算符:

DT[, (grep("keyword", colnames(DT))) := (lapply(.SD, . %>% scale(., center = F))),
    .SDcols = grep("corrupt", colnames(DT))]

单行解决方案版本 2:显式定义 lapply 的函数:

DT[, (grep("keyword", colnames(DT))) := 
     (lapply(.SD, function(x){scale(x, center = F)})), 
     .SDcols = grep("corrupt", colnames(DT))]

修改 - 如果要按组进行,只需使用 by =

DT[  , (grep("keyword", colnames(DT))) := 
              (lapply(.SD, function(x){scale(x, center = F)}))
     , .SDcols = grep("corrupt", colnames(DT))
     , by = Grouping.Variable]

您可以验证:

# Verify that the columns have updated values:
DT[,.SD, .SDcols = grep("corrupt", colnames(DT))]

第 2 部分:分步解决方案:(更通用且更易于遵循)

上述解决方案对于给出的狭义示例显然有效。

作为一项公共服务,我向任何仍在寻找一种方式的人发布此信息

  • 感觉不那么凝缩了;
  • 更容易理解;
  • 更一般地说,从某种意义上说,您可以应用任何您想要的函数,而不必先将值计算到单独的数据表中(nb 在这里工作得很好)

这是执行相同操作的分步方法:

获取数据为Data.Table格式:

# You get a data.table called DT
DT <- as.data.table(df)

然后,处理列名:

# Get the list of names
Reference.Cols <- grep("keyword",colnames(df))



# FOR PEOPLE who want to store both transformed and untransformed values. 
# Create new column names
Reference.Cols.normalized <- Reference.Cols %>% paste(., ".normalized", sep = "")

定义要应用的功能

#Define the function you wish to apply
# Where, normalize is just a function as defined in the question:

normalize <- function(X, 
                      X.mean = mean(X, na.rm = TRUE), 
                      X.sd = sd(X, na.rm = TRUE))
                      {
                          X <- (X - X.mean) / X.sd
                          return(X)
                      }

之后,在 Data.Table 语法中是微不足道的:

# Voila, the newly created set of columns the contain the transformed value, 
DT[, (Reference.Cols.normalized) := lapply(.SD, normalize), .SDcols = Reference.Cols]

核实:

新值存储在名称存储在以下位置的列中:

DT[, .SD, .SDcols = Reference.Cols.normalized]

未转换的值不受损害

DT[, .SD, .SDcols = Reference.Cols]

希望对于那些在一段时间后返回查看代码的人来说,这种更逐步/通用的方法可能会有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM