Стандартизировать столбцы данных в R
У меня есть набор данных под названием spam
который содержит 58 столбцов и примерно 3500 строк данных, связанных со спам-сообщениями.
Я планирую запустить некоторую линейную регрессию для этого набора данных в будущем, но я хотел бы сделать некоторую предварительную обработку заранее и стандартизировать столбцы, чтобы иметь нулевое среднее значение и единичную дисперсию.
Мне сказали, что лучший способ сделать это с помощью R, поэтому я хотел бы спросить, как мне добиться нормализации с помощью R? Я уже правильно загрузил данные, и я просто ищу несколько пакетов или методов для выполнения этой задачи.
16 ответов
Я должен предположить, что вы хотели сказать, что вам нужно среднее значение 0 и стандартное отклонение 1. Если ваши данные находятся в кадре данных, и все столбцы являются числовыми, вы можете просто вызвать scale
функция на данных, чтобы делать то, что вы хотите.
dat <- data.frame(x = rnorm(10, 30, .2), y = runif(10, 3, 5))
scaled.dat <- scale(dat)
# check that we get mean of 0 and sd of 1
colMeans(scaled.dat) # faster version of apply(scaled.dat, 2, mean)
apply(scaled.dat, 2, sd)
Использование встроенных функций классно. Понравился этот кот:
Понимая, что вопрос старый и один ответ принят, я предоставлю другой для справки.
scale
ограничен тем, что он масштабирует все переменные. Приведенное ниже решение позволяет масштабировать только определенные имена переменных, сохраняя при этом другие переменные без изменений (и имена переменных могут генерироваться динамически):
library(dplyr)
set.seed(1234)
dat <- data.frame(x = rnorm(10, 30, .2),
y = runif(10, 3, 5),
z = runif(10, 10, 20))
dat
dat2 <- dat %>% mutate_each_(funs(scale(.) %>% as.vector),
vars=c("y","z"))
dat2
что дает мне это:
> dat
x y z
1 29.75859 3.633225 14.56091
2 30.05549 3.605387 12.65187
3 30.21689 3.318092 13.04672
4 29.53086 3.079992 15.07307
5 30.08582 3.437599 11.81096
6 30.10121 4.621197 17.59671
7 29.88505 4.051395 12.01248
8 29.89067 4.829316 12.58810
9 29.88711 4.662690 19.92150
10 29.82199 3.091541 18.07352
а также
> dat2 <- dat %>% mutate_each_(funs(scale(.) %>% as.vector),
> vars=c("y","z"))
> dat2
x y z
1 29.75859 -0.3004815 -0.06016029
2 30.05549 -0.3423437 -0.72529604
3 30.21689 -0.7743696 -0.58772361
4 29.53086 -1.1324181 0.11828039
5 30.08582 -0.5946582 -1.01827752
6 30.10121 1.1852038 0.99754666
7 29.88505 0.3283513 -0.94806607
8 29.89067 1.4981677 -0.74751378
9 29.88711 1.2475998 1.80753470
10 29.82199 -1.1150515 1.16367556
РЕДАКТИРОВАТЬ: Адресованный комментарий Джулиана: вывод scale
является матрицей Nx1, так что в идеале мы должны добавить as.vector
преобразовать тип матрицы обратно в векторный тип. Спасибо, Джулиан!
Это 3 года. Тем не менее, я чувствую, что должен добавить следующее:
Наиболее распространенная нормализация - это z-преобразование, где вы вычитаете среднее значение и делите на стандартное отклонение вашей переменной. Результат будет иметь среднее значение =0 и SD =1.
Для этого вам не нужен пакет.
zVar <- (myVar - mean(myVar)) / sd(myVar)
Вот и все.
Пакет 'Caret' предоставляет методы для предварительной обработки данных (например, центрирование и масштабирование). Вы также можете использовать следующий код:
library(caret)
# Assuming goal class is column 10
preObj <- preProcess(data[, -10], method=c("center", "scale"))
newData <- predict(preObj, data[, -10])
Более подробная информация: http://www.inside-r.org/node/86978
Когда я использовал решение, изложенное Дэйсоном, вместо того, чтобы в результате получить фрейм данных, я получил вектор чисел (масштабированные значения моего df).
Если у кого-то возникли те же проблемы, вы должны добавить as.data.frame() в код, например так:
df.scaled <- as.data.frame(scale(df))
Я надеюсь, что это будет полезно для людей, имеющих такую же проблему!
Вы можете легко нормализовать данные, также используя функцию data.Normalization в clusterSim package. Это обеспечивает другой метод нормализации данных.
data.Normalization (x,type="n0",normalization="column")
аргументы
Икс
тип вектора, матрицы или набора данных
тип нормализации:
n0 - без нормализации
n1 - стандартизация ((х-среднее) / SD)
n2 - позиционная стандартизация ((x-медиана) / безумная)
n3 - единица измерения ((среднее значение по х) / диапазон)
n3a - позиционная унификация ((x-медиана) / диапазон)
n4 - унификация с нулевым минимумом ((x-min) / диапазон)
n5 - нормализация в диапазоне <-1,1> ((среднее значение x) / максимальное значение (среднее значение x)))
n5a - нормализация положения в диапазоне <-1,1> ((х-медиана) / макс (абс (х-медиана)))
n6 - частное преобразование (x / sd)
n6a - позиционное коэффициентное преобразование (x / mad)
n7 - коэффициент преобразования (х / диапазон)
n8 - коэффициент преобразования (х / макс)
n9 - коэффициент преобразования (х / среднее)
n9a - позиционное коэффициентное преобразование (х / медиана)
n10 - коэффициент преобразования (х / сумма)
n11 - коэффициент преобразования (x / sqrt (SSQ))
n12 - нормализация ((x-среднее)/sqrt(сумма ((x-среднее) ^ 2)))
n12a - нормализация положения ((x-медиана)/sqrt(сумма ((x-медиана) ^ 2)))
n13 - нормализация с нулем, являющимся центральной точкой ((x-midrange)/(range/2))
нормализация
"столбец" - нормализация по переменной, "строка" - нормализация по объекту
С dplyr
v0.7.4 все переменные можно масштабировать с помощью mutate_all()
:
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(tibble)
set.seed(1234)
dat <- tibble(x = rnorm(10, 30, .2),
y = runif(10, 3, 5),
z = runif(10, 10, 20))
dat %>% mutate_all(scale)
#> # A tibble: 10 x 3
#> x y z
#> <dbl> <dbl> <dbl>
#> 1 -0.827 -0.300 -0.0602
#> 2 0.663 -0.342 -0.725
#> 3 1.47 -0.774 -0.588
#> 4 -1.97 -1.13 0.118
#> 5 0.816 -0.595 -1.02
#> 6 0.893 1.19 0.998
#> 7 -0.192 0.328 -0.948
#> 8 -0.164 1.50 -0.748
#> 9 -0.182 1.25 1.81
#> 10 -0.509 -1.12 1.16
Конкретные переменные могут быть исключены с помощью mutate_at()
:
dat %>% mutate_at(scale, .vars = vars(-x))
#> # A tibble: 10 x 3
#> x y z
#> <dbl> <dbl> <dbl>
#> 1 29.8 -0.300 -0.0602
#> 2 30.1 -0.342 -0.725
#> 3 30.2 -0.774 -0.588
#> 4 29.5 -1.13 0.118
#> 5 30.1 -0.595 -1.02
#> 6 30.1 1.19 0.998
#> 7 29.9 0.328 -0.948
#> 8 29.9 1.50 -0.748
#> 9 29.9 1.25 1.81
#> 10 29.8 -1.12 1.16
Создано в 2018-04-24 пакетом представлением (v0.2.0).
Опять же, хотя это старый вопрос, он очень актуален! И я нашел простой способ нормализовать определенные столбцы без необходимости каких-либо пакетов:
normFunc <- function(x){(x-mean(x, na.rm = T))/sd(x, na.rm = T)}
Например
x<-rnorm(10,14,2)
y<-rnorm(10,7,3)
z<-rnorm(10,18,5)
df<-data.frame(x,y,z)
df[2:3] <- apply(df[2:3], 2, normFunc)
Вы увидите, что столбцы y и z нормализованы. Пакеты не нужны:-)
Шкала может использоваться как для полного кадра данных, так и для конкретных столбцов. Для определенных столбцов можно использовать следующий код:
trainingSet[, 3:7] = scale(trainingSet[, 3:7]) # For column 3 to 7
trainingSet[, 8] = scale(trainingSet[, 8]) # For column 8
Полный кадр данных
trainingSet <- scale(trainingSet)
Пакет collapse обеспечивает самую быструю функцию масштабирования - реализованную на C++ с использованием онлайн-алгоритма Welfords:
dat <- data.frame(x = rnorm(1e6, 30, .2),
y = runif(1e6, 3, 5),
z = runif(1e6, 10, 20))
library(collapse)
library(microbenchmark)
microbenchmark(fscale(dat), scale(dat))
Unit: milliseconds
expr min lq mean median uq max neval cld
fscale(dat) 27.86456 29.5864 38.96896 30.80421 43.79045 313.5729 100 a
scale(dat) 357.07130 391.0914 489.93546 416.33626 625.38561 793.2243 100 b
Более того: fscale
S3 является общим для векторов, матриц и кадров данных, а также поддерживает операции сгруппированного и / или взвешенного масштабирования, а также масштабирование до произвольных средних значений и стандартных отклонений.
dplyr
Пакет имеет две функции, которые делают это.
> require(dplyr)
Чтобы изменить определенные столбцы таблицы данных, вы можете использовать функцию mutate_at()
, Чтобы изменить все столбцы, вы можете использовать mutate_all
,
Ниже приведен краткий пример использования этих функций для стандартизации данных.
Мутируйте определенные столбцы:
dt = data.table(a = runif(3500), b = runif(3500), c = runif(3500))
dt = data.table(dt %>% mutate_at(vars("a", "c"), scale)) # can also index columns by number, e.g., vars(c(1,3))
> apply(dt, 2, mean)
a b c
1.783137e-16 5.064855e-01 -5.245395e-17
> apply(dt, 2, sd)
a b c
1.0000000 0.2906622 1.0000000
Мутировать все столбцы:
dt = data.table(a = runif(3500), b = runif(3500), c = runif(3500))
dt = data.table(dt %>% mutate_all(scale))
> apply(dt, 2, mean)
a b c
-1.728266e-16 9.291994e-17 1.683551e-16
> apply(dt, 2, sd)
a b c
1 1 1
Прежде чем мне удалось найти эту ветку, у меня была такая же проблема. У меня были зависимые от пользователя типы столбцов, поэтому я написал for
цикл проходит через них и получает необходимые столбцы scale
"D. Возможно, есть лучшие способы сделать это, но это решило проблему просто отлично:
for(i in 1:length(colnames(df))) {
if(class(df[,i]) == "numeric" || class(df[,i]) == "integer") {
df[,i] <- as.vector(scale(df[,i])) }
}
as.vector
это необходимая часть, потому что оказалось scale
делает rownames x 1
матрица, которая обычно не то, что вы хотите иметь в своем data.frame
,
@BBKim дал в значительной степени лучший ответ, но это можно сделать короче. Я удивлен, что его еще никто не придумал.
dat <- data.frame(x = rnorm(10, 30, .2), y = runif(10, 3, 5))
dat <- apply(dat, 2, function(x) (x - mean(x)) / sd(x))
Используйте пакет "Recommenderlab". Загрузите и установите пакет. Этот пакет имеет команду "Нормализовать" во встроенном. Это также позволяет вам выбрать один из многих методов нормализации, а именно "центр" или "Z-счет". Следуйте следующему примеру:
## create a matrix with ratings
m <- matrix(sample(c(NA,0:5),50, replace=TRUE, prob=c(.5,rep(.5/6,6))),nrow=5, ncol=10, dimnames = list(users=paste('u', 1:5, sep=”), items=paste('i', 1:10, sep=”)))
## do normalization
r <- as(m, "realRatingMatrix")
#here, 'centre' is the default method
r_n1 <- normalize(r)
#here "Z-score" is the used method used
r_n2 <- normalize(r, method="Z-score")
r
r_n1
r_n2
## show normalized data
image(r, main="Raw Data")
image(r_n1, main="Centered")
image(r_n2, main="Z-Score Normalization")
Приведенный ниже код может быть кратчайшим способом добиться этого.
dataframe <- apply(dataframe, 2, scale)
Функция нормализации из пакета BBMisc была для меня правильным инструментом, поскольку она может работать со значениями NA.
Вот как им пользоваться:
Учитывая следующий набор данных,
ASR_API <- c("CV", "F", "IER", "LS-c", "LS-o")
Human <- c(NA, 5.8, 12.7, NA, NA)
Google <- c(23.2, 24.2, 16.6, 12.1, 28.8)
GoogleCloud <- c(23.3, 26.3, 18.3, 12.3, 27.3)
IBM <- c(21.8, 47.6, 24.0, 9.8, 25.3)
Microsoft <- c(29.1, 28.1, 23.1, 18.8, 35.9)
Speechmatics <- c(19.1, 38.4, 21.4, 7.3, 19.4)
Wit_ai <- c(35.6, 54.2, 37.4, 19.2, 41.7)
dt <- data.table(ASR_API,Human, Google, GoogleCloud, IBM, Microsoft, Speechmatics, Wit_ai)
> dt
ASR_API Human Google GoogleCloud IBM Microsoft Speechmatics Wit_ai
1: CV NA 23.2 23.3 21.8 29.1 19.1 35.6
2: F 5.8 24.2 26.3 47.6 28.1 38.4 54.2
3: IER 12.7 16.6 18.3 24.0 23.1 21.4 37.4
4: LS-c NA 12.1 12.3 9.8 18.8 7.3 19.2
5: LS-o NA 28.8 27.3 25.3 35.9 19.4 41.7
нормализованные значения можно получить так:
> dtn <- normalize(dt, method = "standardize", range = c(0, 1), margin = 1L, on.constant = "quiet")
> dtn
ASR_API Human Google GoogleCloud IBM Microsoft Speechmatics Wit_ai
1: CV NA 0.3361245 0.2893457 -0.28468670 0.3247336 -0.18127203 -0.16032655
2: F -0.7071068 0.4875320 0.7715885 1.59862532 0.1700986 1.55068347 1.31594762
3: IER 0.7071068 -0.6631646 -0.5143923 -0.12409420 -0.6030768 0.02512682 -0.01746131
4: LS-c NA -1.3444981 -1.4788780 -1.16064578 -1.2680075 -1.24018782 -1.46198764
5: LS-o NA 1.1840062 0.9323361 -0.02919864 1.3762521 -0.15435044 0.32382788
где метод, рассчитанный вручную, просто игнорирует столбцы, содержащие НА:
> dt %>% mutate(normalizedHuman = (Human - mean(Human))/sd(Human)) %>%
+ mutate(normalizedGoogle = (Google - mean(Google))/sd(Google)) %>%
+ mutate(normalizedGoogleCloud = (GoogleCloud - mean(GoogleCloud))/sd(GoogleCloud)) %>%
+ mutate(normalizedIBM = (IBM - mean(IBM))/sd(IBM)) %>%
+ mutate(normalizedMicrosoft = (Microsoft - mean(Microsoft))/sd(Microsoft)) %>%
+ mutate(normalizedSpeechmatics = (Speechmatics - mean(Speechmatics))/sd(Speechmatics)) %>%
+ mutate(normalizedWit_ai = (Wit_ai - mean(Wit_ai))/sd(Wit_ai))
ASR_API Human Google GoogleCloud IBM Microsoft Speechmatics Wit_ai normalizedHuman normalizedGoogle
1 CV NA 23.2 23.3 21.8 29.1 19.1 35.6 NA 0.3361245
2 F 5.8 24.2 26.3 47.6 28.1 38.4 54.2 NA 0.4875320
3 IER 12.7 16.6 18.3 24.0 23.1 21.4 37.4 NA -0.6631646
4 LS-c NA 12.1 12.3 9.8 18.8 7.3 19.2 NA -1.3444981
5 LS-o NA 28.8 27.3 25.3 35.9 19.4 41.7 NA 1.1840062
normalizedGoogleCloud normalizedIBM normalizedMicrosoft normalizedSpeechmatics normalizedWit_ai
1 0.2893457 -0.28468670 0.3247336 -0.18127203 -0.16032655
2 0.7715885 1.59862532 0.1700986 1.55068347 1.31594762
3 -0.5143923 -0.12409420 -0.6030768 0.02512682 -0.01746131
4 -1.4788780 -1.16064578 -1.2680075 -1.24018782 -1.46198764
5 0.9323361 -0.02919864 1.3762521 -0.15435044 0.32382788
(normalizedHuman составляет список НА...)
Что касается выбора конкретных столбцов для расчета, можно использовать общий метод, например этот:
data_vars <- df_full %>% dplyr::select(-ASR_API,-otherVarNotToBeUsed)
meta_vars <- df_full %>% dplyr::select(ASR_API,otherVarNotToBeUsed)
data_varsn <- normalize(data_vars, method = "standardize", range = c(0, 1), margin = 1L, on.constant = "quiet")
dtn <- cbind(meta_vars,data_varsn)