Стандартизация фрейма данных с использованием среднего значения и SD из другого фрейма данных - PullRequest
0 голосов
/ 13 июля 2020

У меня есть фрейм данных, в котором хранятся среднее и стандартное отклонение для 4 (или любого числа N) переменных

mean_sd_df <- data.frame(variable = c('x1', 'x2', 'x3', 'x4'),
                         mean_var = c(2, 3, 4, 8),
                         sd_var = c(0.2, 0.3, 0.4, 0.6))

У меня есть другой фрейм данных, в котором есть значения четырех вышеуказанных переменных, которые должны быть стандартизировано с использованием среднего значения и SD из приведенного выше фрейма данных

set.seed(123)  

dat.mat <- data.frame(x1 = sample(1:10, 4),
                      x2 = sample(1:10, 4),
                      x3 = sample(1:10, 4),
                      x4 = sample(1:10, 4))
  

Вот как я делаю стандартизацию.

dat.mat[ , 1] <- (dat.mat[ , 1] - mean_sd_df[1, 'mean_var'])/mean_sd_df[1, 'sd_var']
dat.mat[ , 2] <- (dat.mat[ , 2] - mean_sd_df[2, 'mean_var'])/mean_sd_df[2, 'sd_var']
dat.mat[ , 3] <- (dat.mat[ , 3] - mean_sd_df[3, 'mean_var'])/mean_sd_df[3, 'sd_var']
dat.mat[ , 4] <- (dat.mat[ , 4] - mean_sd_df[4, 'mean_var'])/mean_sd_df[4, 'sd_var']

Если у меня много переменных, это может стать большим, так интересно есть ли более простой способ сделать это?

Ответы [ 2 ]

0 голосов
/ 13 июля 2020

Вот вариант с pivot_longer/pivot_wider. Измените форму данных в «длинный» формат с помощью pivot_longer, left_join с набором данных «mean_sd_sf», стандартизируйте и измените форму обратно в «широкий» формат с помощью pivot_wider

library(dplyr)
library(tidyr)
dat.mat %>%
    mutate(rn = row_number()) %>% 
    pivot_longer(cols = -rn) %>% 
    left_join(mean_sd_df, by = c('name' = 'variable')) %>% 
    transmute(rn, name, value = (value - mean_var)/sd_var) %>% 
    pivot_wider(names_from = name, values_from = value) %>% 
    select(-rn)
# A tibble: 4 x 4
#     x1    x2    x3     x4
#  <dbl> <dbl> <dbl>  <dbl>
#1     5 10      5    -5   
#2    40  6.67  12.5  -8.33
#3     0  3.33  -5     1.67
#4    30 23.3   -2.5 -11.7 

Или в base R с Map

dat.mat[] <- Map(function(x, y, z) (x - y)/z, dat.mat, 
           mean_sd_df$mean_var, mean_sd_df$sd_var)
0 голосов
/ 13 июля 2020

Вы можете определить функцию, которая действует в столбце и запускать ее во всех столбцах, используя lapply:

standardize <- function(col, df, mean_sd_df){
      ind_row <- which(mean_sd_df$variable == col)
      df[[col]] <- (df[[col]] - mean_sd_df[ind_row, "mean_var"])/mean_sd_df[ind_row, "sd_var"]
      return(df[[col]])
    }
    
dat.mat <- as.data.frame(lapply(names(dat.mat), standardize,
df=dat.mat,
mean_sd_df=mean_sd_df),
col.names = names(dat.mat))

Output

x1        x2   x3         x4
1  5 10.000000  5.0  -5.000000
2 40  6.666667 12.5  -8.333333
3  0  3.333333 -5.0   1.666667
4 30 23.333333 -2.5 -11.666667
...