Membakukan kolom data dalam R


209

Saya memiliki dataset spamyang berisi 58 kolom dan sekitar 3500 baris data yang terkait dengan pesan spam.

Saya berencana menjalankan beberapa regresi linier pada dataset ini di masa depan, tetapi saya ingin melakukan beberapa pra-pemrosesan sebelumnya dan menstandarisasi kolom untuk memiliki mean nol dan varian unit.

Saya telah diberitahu cara terbaik untuk melakukan ini adalah dengan R, jadi saya ingin bertanya bagaimana saya bisa mencapai normalisasi dengan R ? Saya sudah mendapatkan data dengan benar dan saya hanya mencari beberapa paket atau metode untuk melakukan tugas ini.

Jawaban:


533

Saya harus berasumsi bahwa Anda bermaksud mengatakan bahwa Anda menginginkan nilai rata-rata 0 dan standar deviasi 1. Jika data Anda dalam bingkai data dan semua kolom adalah angka, Anda dapat memanggil scalefungsi pada data untuk melakukan apa yang Anda inginkan.

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)

Menggunakan fungsi bawaan sangat berkelas. Seperti kucing ini:

masukkan deskripsi gambar di sini


24
Ya kesalahan saya yang saya maksud 0 mean. Dan itu kucing yang cukup berkelas
Hoser

8
Memberi +1 menggunakan bisa lambat juga seperti kucing gemuk ini :) (colMeans here)
agstudy

1
@ agstudy Cukup adil. Saya harus terbiasa menggunakan colMeans / colSums lebih banyak. Saya kira saya tidak memikirkannya kecuali saya berada dalam situasi di mana itu benar-benar penting ...
Dason

137
situs ini membutuhkan lebih banyak kucing +1
LoveMeow

35
Peringatan: skala juga mengubah bingkai data menjadi sebuah matriks
Julian Karls

89

Menyadari bahwa pertanyaannya sudah lama dan satu jawaban diterima, saya akan memberikan jawaban lain untuk referensi.

scaledibatasi oleh fakta bahwa ia menskala semua variabel . Solusi di bawah ini memungkinkan untuk menskala hanya nama variabel tertentu sambil mempertahankan variabel lain tidak berubah (dan nama variabel dapat dihasilkan secara dinamis):

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_at(c("y", "z"), ~(scale(.) %>% as.vector))
dat2

yang memberi saya ini:

> 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

dan

> dat2 <- dat %>% mutate_at(c("y", "z"), ~(scale(.) %>% as.vector))
> 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

EDIT 1 (2016) : Alamat komentar Julian: output dari scaleadalah matriks Nx1 jadi idealnya kita harus menambahkan as.vectoruntuk mengubah tipe matriks kembali menjadi tipe vektor. Julian terima kasih!

EDIT 2 (2019) : Mengutip komentar Duccio A.: Untuk dplyr terbaru (versi 0.8) Anda perlu mengubah dplyr :: funcs dengan daftar, sepertidat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))

EDIT 3 (2020) : Terima kasih kepada @mj_whales: solusi lama sudah usang dan sekarang kita perlu menggunakan mutate_at.


Metode ini bekerja dengan sempurna, khususnya ketika saya memiliki kombinasi variabel kategorikal dan numerik. Saya hanya punya satu pertanyaan apa artinya operator ini "%>%"?
nooshinha

9
@ weber85, ini adalah operator "pipa" (dari pemrograman fungsional). Alih-alih menulis f(g(x))itu akan terlihat lebih bagus jika ada yang menulis x %>% g %>% f. Dengan kata lain, dat %>% mutate_each_(funs(scale),vars=c("y","z"))itu adil mutate_each_(dat,funs(scale),vars=c("y","z")). Operator sangat membantu ketika rantai sangat panjang karena f(g(h(i(j(x)))))bisa sangat sulit dibaca.
akhmed

Dengan menggunakan pendekatan ini, kolom di mana skala diterapkan untuk ditransfer dari vektor (numerik kelas) ke matriks Nx1. Ini mungkin (dan dalam kasus saya memang) menyebabkan beberapa kesalahan dalam paket yang menganggap setiap kolom data.frame adalah vektor.
Julian Karls

2
Untuk terbaru dplyr(versi 0.8) yang Anda butuhkan untuk perubahan dplyr::funcsdengan list, sepertidat %>% mutate_each_(list(~scale(.) %>% as.vector), vars=c("y","z"))
Duccio A

2
mutate_each_()sekarang sudah ditinggalkan. Anda bisa menggunakannya mutate_at(). Cara baru untuk melakukannya adalah:dat2 <- dat %>% mutate_at(c("y", "z"), scale)
mj_whales

60

Ini berumur 3 tahun. Namun, saya merasa saya harus menambahkan yang berikut:

Normalisasi yang paling umum adalah transformasi-z , di mana Anda mengurangi mean dan membaginya dengan deviasi standar variabel Anda. Hasilnya akan memiliki mean = 0 dan sd = 1.

Untuk itu, Anda tidak perlu paket apa pun.

zVar <- (myVar - mean(myVar)) / sd(myVar)

Itu dia.


Benar-benar cara sederhana untuk melakukan ini. Terima kasih
Pedro Neves

Dan merek menggunakannya dplyr jauh lebih mudah: mutate(var = (var - mean(var))/sd(var)).
RobertMyles

Tetapi dapatkah ini digunakan untuk mendapatkan skor-z untuk dua variabel?
lf_araujo

untuk mendenormalisasi myVar <- (zVar * sd(zVar)) + mean(zVar), kan?
Artur_Indio

4
@Artur_Indio Hampir: newVar <- (zVar * sd(myVar)) + mean(myVar). Anda harus menggunakan mean / sd asli. Saat Anda menulisnya, Anda akan berlipat ganda sd(zVar)=1dan menambahkan mean(zVar)=0, jadi tidak ada yang akan berubah :)
random_forest_fanatic

24

Paket 'Caret' menyediakan metode untuk memproses data sebelumnya (mis. Pemusatan dan penskalaan). Anda juga dapat menggunakan kode berikut:

library(caret)
# Assuming goal class is column 10
preObj <- preProcess(data[, -10], method=c("center", "scale"))
newData <- predict(preObj, data[, -10])

Lebih detail: http://www.inside-r.org/node/86978


17

Ketika saya menggunakan solusi yang dinyatakan oleh Dason, alih-alih mendapatkan data frame sebagai hasilnya, saya mendapat vektor angka (nilai skala dari df saya).

Jika seseorang mengalami masalah yang sama, Anda harus menambahkan as.data.frame () ke kode, seperti ini:

df.scaled <- as.data.frame(scale(df))

Saya harap ini akan bermanfaat bagi ppl yang memiliki masalah yang sama!


Solusi bagus! Jika seseorang ingin mengecualikan kolom dari yang telah diskalakan, Anda dapat melakukannya seperti ini: di train_dt[-24] <- scale(train_dt[-24]) mana "24" adalah nomor kolom yang akan dikecualikan
NetEmmanuel

13

Anda dapat dengan mudah menormalkan data juga menggunakan data. Fungsi normalisasi dalam paket clusterSim. Ini menyediakan metode normalisasi data yang berbeda.

    data.Normalization (x,type="n0",normalization="column")

Argumen

x jenis
vektor, matriks atau dataset tipe
normalisasi: n0 - tanpa normalisasi

n1 - standardisasi ((x-mean) / sd)

n2 - standardisasi posisi ((x-median) / mad)

n3 - unitisasi ((rata-rata x) / rentang)

n3a - unitisasi posisi ((x-median) / range)

n4 - unitisasi dengan nol minimum ((x-min) / range)

n5 - normalisasi dalam kisaran <-1,1> ((x-mean) / max (abs (x-mean)))

n5a - normalisasi posisi dalam kisaran <-1,1> ((x-median) / max (abs (x-median)))

n6 - transformasi hasil bagi (x / sd)

n6a - transformasi hasil bagi posisi (x / mad)

n7 - transformasi hasil bagi (x / rentang)

n8 - transformasi hasil bagi (x / maks)

n9 - transformasi hasil bagi (x / rata-rata)

n9a - transformasi hasil bagi posisi (x / median)

n10 - transformasi hasil bagi (x / jumlah)

n11 - transformasi hasil bagi (x / sqrt (SSQ))

n12 - normalisasi ((rata-rata x) / sqrt (jumlah ((rata-rata x) ^ 2))))

n12a - normalisasi posisi ((x-median) / sqrt (jumlah ((x-median) ^ 2))))

n13 - normalisasi dengan nol menjadi titik pusat ((x-midrange) / (rentang / 2))

normalisasi
"kolom" - normalisasi menurut variabel, "baris" - normalisasi menurut objek


paket ini tidak tersedia untuk R versi 3.4.3
JdP

11

Dengan dplyrv0.7.4 semua variabel dapat diskalakan dengan menggunakan 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

Variabel spesifik dapat dikecualikan menggunakan 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

Dibuat pada 2018-04-24 oleh paket reprex (v0.2.0).


9

Sekali lagi, meskipun ini adalah pertanyaan lama, ini sangat relevan! Dan saya telah menemukan cara sederhana untuk menormalkan kolom-kolom tertentu tanpa perlu paket apa pun:

normFunc <- function(x){(x-mean(x, na.rm = T))/sd(x, na.rm = T)}

Sebagai contoh

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)

Anda akan melihat bahwa kolom y dan z telah dinormalisasi. Tidak perlu paket :-)


8

Skala dapat digunakan untuk frame data lengkap dan kolom tertentu. Untuk kolom tertentu, kode berikut dapat digunakan:

trainingSet[, 3:7] = scale(trainingSet[, 3:7]) # For column 3 to 7
trainingSet[, 8] = scale(trainingSet[, 8]) # For column 8 

Bingkai data lengkap

trainingSet <- scale(trainingSet)

3

The dplyrpaket memiliki dua fungsi yang melakukan hal ini.

> require(dplyr)

Untuk bermutasi kolom tertentu dari tabel data, Anda dapat menggunakan fungsi ini mutate_at(). Untuk bermutasi semua kolom, Anda dapat menggunakan mutate_all.

Berikut ini adalah contoh singkat untuk menggunakan fungsi-fungsi ini untuk membakukan data.

Mutasi kolom tertentu:

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 

Matikan semua kolom:

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 

1

Sebelum saya menemukan utas ini, saya memiliki masalah yang sama. Saya memiliki tipe kolom yang bergantung pada pengguna, jadi saya menulis satu forloop melalui mereka dan mendapatkan kolom yang diperlukan scaled. Mungkin ada cara yang lebih baik untuk melakukannya, tetapi ini menyelesaikan masalah dengan baik:

 for(i in 1:length(colnames(df))) {
        if(class(df[,i]) == "numeric" || class(df[,i]) == "integer") {
            df[,i] <- as.vector(scale(df[,i])) }
        }

as.vectoradalah bagian dibutuhkan, karena ternyata scaletidak rownames x 1matriks yang biasanya tidak apa yang ingin Anda miliki di Anda data.frame.


0

Gunakan paket "recommenderlab". Unduh dan instal paket. Paket ini memiliki perintah "Normalisasi" di dalamnya. Anda juga dapat memilih salah satu dari banyak metode normalisasi yaitu 'center' atau 'Z-score'. Ikuti contoh berikut:

## 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=&rdquo;), items=paste('i', 1:10, sep=&rdquo;)))

## 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")

1
Jawaban ini tidak menjawab pertanyaan.
f0nzie

0

Fungsi normalisasi dari paket BBMisc adalah alat yang tepat bagi saya karena dapat menangani nilai-nilai NA.

Berikut cara menggunakannya:

Diberikan dataset berikut,

    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

nilai yang dinormalisasi dapat diperoleh seperti ini:

> 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

di mana metode perhitungan tangan mengabaikan kolmun yang mengandung NAS:

> 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 dibuat daftar NAS ...)

mengenai pemilihan kolom khusus untuk perhitungan, metode generik dapat digunakan seperti ini:

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)

0

@BBKim cukup banyak memberikan jawaban terbaik, tetapi itu bisa dilakukan lebih pendek. Saya terkejut belum ada yang datang dengan itu.

dat <- data.frame(x = rnorm(10, 30, .2), y = runif(10, 3, 5)) dat <- apply(dat, 2, function(x) (x - mean(x)) / sd(x))

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.