簡體   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