【问题标题】:R Standardizing numeric variables in dataframe while retaining factor variablesR标准化数据框中的数字变量,同时保留因子变量
【发布时间】:2018-07-15 22:24:18
【问题描述】:

我在 R 中加载了一个数据框 (dcc),我已将其范围缩小到完整的案例。

str(dcc)

'data.frame':   41715 obs. of  9 variables:
 $ XCoord                  : num  661382 661412 661442 661472 661502 ...
 $ YCoord                  : num  648092 648092 648092 648092 648092 ...
 $ OBJECTID                : int  1 2 3 4 5 6 7 8 9 10 ...
 $ POINTID                 : int  1 2 3 4 5 6 7 8 9 10 ...
 $ GRID_CODE               : int  0 0 0 0 0 0 0 0 0 0 ...
 $ APPL_COST_DIST_RIV_COAST: num  21350 21674 22185 22748 23448 ...
 $ APPL_DEM30              : int  785 793 792 769 765 777 784 789 781 751 ...
 $ APPL_DEM30_SLOPE        : num  19.7 13.3 18.6 23.2 21 ...
 $ APPL_SITE_NONSITE       : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...

我想通过减去平均值并除以标准差来标准化数字和整数变量。当我应用以下代码时,我无意中从数据框中删除了因子变量 APPL_SITE_NONSITE:

ind <- sapply(dcc, is.numeric)
dcc.s<-sapply(dcc[,ind], function(x) (x-mean(x))/sd(x))
dcc.s<-data.frame(dcc.s)

如果我没记错的话,这是因为该变量的 ind=FALSE。似乎我需要一些 for 循环和 if/else 语句的组合来标准化数值变量并单独保留因子变量。我尝试了许多排列,但不断出错。例如以下代码:

dcc.s <- for (i in 1:ncol(dcc)){ sapply(dcc[,i],
if (is.numeric(dcc[,i])==TRUE) {
function(x) (x-mean(x))/sd(x) }
 else {dcc[,i]})
}

返回错误:

match.fun(FUN) 中的错误: c("'if (is.numeric(dcc[, i]) == TRUE) {' 不是函数、字符或符号", "' function(x) (x - mean(x))/sd(x )' 不是函数、字符或符号", "'} else {' 不是函数、字符或符号", "' dcc[, i]' 不是函数、字符或符号", "'}'不是函数、字符或符号")

也许这是一个简单的格式错误或放错位置的括号,但我完全被卡住了。如果有更优雅的方法可以做到这一点,我愿意接受其他方法。任何帮助将非常感激。

【问题讨论】:

    标签: r standardized


    【解决方案1】:

    这是dplyrscale 解决方案。

    dplyr
    require(dplyr)
    df %>% mutate_if(is.numeric, scale)
    #   a  runif(20)    rnorm(20)
    #1  y  0.5783877 -0.004177104
    #2  n -0.2344854 -0.866626472
    #3  m  1.5629961  1.526857969
    #4  h  0.9648646 -1.557975547
    #5  u -0.7212756  0.533400304
    #6  u  1.4753675 -0.072289864
    #7  b  0.5346870 -0.464299111
    #8  l -0.4287559  0.426600473
    #9  m -1.2050841 -0.880135405
    #10 h -0.6150410 -0.040636433
    #11 r  1.3768249 -0.719785950
    #12 a -1.3929511  0.083010969
    #13 a -0.4422665  0.385574213
    #14 l -0.7719473 -0.934716525
    #15 m  1.4483803  0.131974911
    #16 k  0.6291919  2.598581195
    #17 k -1.0356817 -1.018890381
    #18 s -1.0960083  1.560216350
    #19 y -0.8826702 -0.367821579
    #20 v  0.2554671 -0.318862011
           
    

    对于dplyr >= 1.0.0

    df %>% mutate(across(where(is.numeric), scale))
    

    注意scale(x) 的作用与(x - mean(x)) / sd(x) 相同;如果您想根据不同的指标进行扩展(例如,基于中位数和 MAD 的稳健/修改 Z 分数),您可以使用 sweep 来实现。


    样本数据

    set.seed(2017);
    df <- cbind.data.frame(a = factor(sample(letters, 20, replace = T)), runif(20), rnorm(20));
    

    【讨论】:

    • @Onyambu 不确定你的意思; is.numeric(as.integer(10)) 将返回 TRUE,因此这也将扩展 int
    【解决方案2】:

    您需要使用rapply 而不是sapply

    set.seed(1)
    > df=data.frame(A=rnorm(10),b=1:10,C=as.factor(rep(1:2,5)))
    > str(df)
    'data.frame':   10 obs. of  3 variables:
     $ A: num  -0.626 0.184 -0.836 1.595 0.33 ...
     $ b: int  1 2 3 4 5 6 7 8 9 10
     $ C: Factor w/ 2 levels "1","2": 1 2 1 2 1 2 1 2 1 2
    

    你需要使用的代码:

    > D=rapply(df,scale,c("numeric","integer"),how="replace")
    > D
                 A          b C
    1  -0.97190653 -1.4863011 1
    2   0.06589991 -1.1560120 2
    3  -1.23987805 -0.8257228 1
    4   1.87433300 -0.4954337 2
    5   0.25276523 -0.1651446 1
    6  -1.22045645  0.1651446 2
    7   0.45507643  0.4954337 1
    8   0.77649606  0.8257228 2
    9   0.56826358  1.1560120 1
    10 -0.56059319  1.4863011 2
    > str(D)
    'data.frame':   10 obs. of  3 variables:
     $ A: num [1:10, 1] -0.9719 0.0659 -1.2399 1.8743 0.2528 ...
      ..- attr(*, "scaled:center")= num 0.132
      ..- attr(*, "scaled:scale")= num 0.781
     $ b: num [1:10, 1] -1.486 -1.156 -0.826 -0.495 -0.165 ...
      ..- attr(*, "scaled:center")= num 5.5
      ..- attr(*, "scaled:scale")= num 3.03
     $ C: Factor w/ 2 levels "1","2": 1 2 1 2 1 2 1 2 1 2
    > 
    

    【讨论】:

      【解决方案3】:
      ind <- sapply(dcc, is.numeric)
      dcc.s <- as.data.frame(lapply(dcc[,ind], function(x) (x-mean(x))/sd(x)))
      dcc.s <- cbind(dcc, dcc.s)
      

      如果您不需要“旧”数据框,您也可以这样做

      ind <- sapply(dcc, is.numeric)
      dcc[,ind] <- vapply(dcc[,ind], function(x) (x-mean(x))/sd(x))
      

      【讨论】:

      • 谢谢,@Georgery。当我使用 lapply 时,第二个代码块运行良好: ind
      猜你喜欢
      • 2016-09-18
      • 1970-01-01
      • 2016-08-10
      • 1970-01-01
      • 1970-01-01
      • 2019-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多