首页 文章

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

提问于
浏览
2

如何拥有一个主要使用数值的data.table,只转换列的一个子集并将它们放回到原始数据表中?通常,我不想将任何摘要统计信息添加为单独的列,只需交换已转换的列 .

假设我们有一个DT . 它有1列名称和10列数字值 . 我感兴趣的是对该数据表的每一行使用基数R的“缩放”功能,但仅适用于那10个数字列 .

并扩展这一点 . 如果我有一个包含更多列的数据表怎么办?我需要使用 column names 告诉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?

2 回答

  • 2

    如果您需要的是真正按行扩展,您可以尝试分两步:

    # 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))]
    
  • 0

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

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

    One-line Solution Version 1: Use magrittR and the pipe operator:

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

    One-line Solution Version 2: Explicitly defines the function for the lapply:

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

    Modification - If you want to do it by group, just use the by =

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

    You can verify:

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

    第2部分:循序渐进的解决方案:(更一般,更容易理解)

    上述解决方案对于给出的狭窄示例清楚地起作用 .

    作为一项公共服务,我正在为那些仍在寻找方式的人发布此信息

    • 感觉有点不那么浓缩;

    • 更容易理解;

    • 更一般,在某种意义上说,你可以应用你想要的任何函数,而不必先将值计算到一个单独的数据表中(其中,n.b . 在这里完美地工作)

    这是一步一步的做法:

    将数据导入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]
    未经改造的 Value 没有受到伤害
    DT[, .SD, .SDcols = Reference.Cols]

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

相关问题