Saya memiliki variabel dalam kerangka data di mana salah satu bidang biasanya memiliki 7-8 nilai. Saya ingin menyusunnya 3 atau 4 kategori baru dalam variabel baru dalam kerangka data. Apa pendekatan terbaik?
Saya akan menggunakan pernyataan CASE jika saya menggunakan alat seperti SQL tetapi tidak yakin bagaimana cara menyerang ini di R.
Bantuan apa pun yang Anda berikan akan sangat dihargai!
dput()
b) Apakah Anda menginginkan solusi dalam basis R, dplyr, data.table, tidyverse ...?Jawaban:
case_when()
, yang ditambahkan ke dplyr pada Mei 2016, memecahkan masalah ini dengan cara yang mirip denganmemisc::cases()
.Sebagai contoh:
library(dplyr) mtcars %>% mutate(category = case_when( .$cyl == 4 & .$disp < median(.$disp) ~ "4 cylinders, small displacement", .$cyl == 8 & .$disp > median(.$disp) ~ "8 cylinders, large displacement", TRUE ~ "other" ) )
Pada dplyr 0.7.0,
mtcars %>% mutate(category = case_when( cyl == 4 & disp < median(disp) ~ "4 cylinders, small displacement", cyl == 8 & disp > median(disp) ~ "8 cylinders, large displacement", TRUE ~ "other" ) )
sumber
.$
di depan setiap kolom..$
tidak lagi diperlukan. Pada saat jawaban ini pertama kali ditulis, memang begitu.switch
, ini memungkinkan Anda membuat urutan ekspresi alih-alih kunci untuk kasus.Lihat
cases
fungsi darimemisc
paket. Ini mengimplementasikan fungsionalitas kasus dengan dua cara berbeda untuk menggunakannya. Dari contoh di dalam paket:z1=cases( "Condition 1"=x<0, "Condition 2"=y<0,# only applies if x >= 0 "Condition 3"=TRUE )
dimana
x
dany
adalah dua vektor.Referensi: paket memisc , contoh kasus
sumber
Jika Anda mendapatkannya,
factor
Anda dapat mengubah level dengan metode standar:df <- data.frame(name = c('cow','pig','eagle','pigeon'), stringsAsFactors = FALSE) df$type <- factor(df$name) # First step: copy vector and make it factor # Change levels: levels(df$type) <- list( animal = c("cow", "pig"), bird = c("eagle", "pigeon") ) df # name type # 1 cow animal # 2 pig animal # 3 eagle bird # 4 pigeon bird
Anda bisa menulis fungsi sederhana sebagai pembungkus:
changelevels <- function(f, ...) { f <- as.factor(f) levels(f) <- list(...) f } df <- data.frame(name = c('cow','pig','eagle','pigeon'), stringsAsFactors = TRUE) df$type <- changelevels(df$name, animal=c("cow", "pig"), bird=c("eagle", "pigeon"))
sumber
x
di baris terakhirchangelevels
?Berikut cara menggunakan
switch
pernyataan tersebut:df <- data.frame(name = c('cow','pig','eagle','pigeon'), stringsAsFactors = FALSE) df$type <- sapply(df$name, switch, cow = 'animal', pig = 'animal', eagle = 'bird', pigeon = 'bird') > df name type 1 cow animal 2 pig animal 3 eagle bird 4 pigeon bird
Satu kelemahan dari ini adalah Anda harus tetap menulis nama kategori (
animal
, dll) untuk setiap item. Secara sintaksis lebih mudah untuk dapat mendefinisikan kategori kita seperti di bawah ini (lihat pertanyaan yang sangat mirip Bagaimana cara menambahkan kolom dalam bingkai data di R )myMap <- list(animal = c('cow', 'pig'), bird = c('eagle', 'pigeon'))
dan kami ingin "membalik" pemetaan ini. Saya menulis fungsi invMap saya sendiri:
invMap <- function(map) { items <- as.character( unlist(map) ) nams <- unlist(Map(rep, names(map), sapply(map, length))) names(nams) <- items nams }
dan kemudian balikkan peta di atas sebagai berikut:
> invMap(myMap) cow pig eagle pigeon "animal" "animal" "bird" "bird"
Dan kemudian mudah menggunakan ini untuk menambahkan
type
kolom di bingkai data:df <- transform(df, type = invMap(myMap)[name]) > df name type 1 cow animal 2 pig animal 3 eagle bird 4 pigeon bird
sumber
Saya tidak melihat proposal untuk 'saklar'. Contoh kode (jalankan):
x <- "three" y <- 0 switch(x, one = {y <- 5}, two = {y <- 12}, three = {y <- 432}) y
sumber
Imho, kode paling lugas dan universal:
dft=data.frame(x = sample(letters[1:8], 20, replace=TRUE)) dft=within(dft,{ y=NA y[x %in% c('a','b','c')]='abc' y[x %in% c('d','e','f')]='def' y[x %in% 'g']='g' y[x %in% 'h']='h' })
sumber
y = 'else'
. Elemen yang tidak memenuhi ketentuan lebih lanjut akan tetap tidak berubah.Ada
switch
pernyataan tetapi saya tidak pernah bisa membuatnya bekerja seperti yang saya kira seharusnya. Karena Anda belum memberikan contoh, saya akan membuatnya menggunakan variabel faktor:dft <-data.frame(x = sample(letters[1:8], 20, replace=TRUE)) levels(dft$x) [1] "a" "b" "c" "d" "e" "f" "g" "h"
Jika Anda menentukan kategori yang Anda inginkan dalam urutan yang sesuai dengan penugasan ulang, Anda dapat menggunakan faktor atau variabel numerik sebagai indeks:
c("abc", "abc", "abc", "def", "def", "def", "g", "h")[dft$x] [1] "def" "h" "g" "def" "def" "abc" "h" "h" "def" "abc" "abc" "abc" "h" "h" "abc" [16] "def" "abc" "abc" "def" "def" dft$y <- c("abc", "abc", "abc", "def", "def", "def", "g", "h")[dft$x] str(dft) 'data.frame': 20 obs. of 2 variables: $ x: Factor w/ 8 levels "a","b","c","d",..: 4 8 7 4 6 1 8 8 5 2 ... $ y: chr "def" "h" "g" "def" ...
Saya kemudian mengetahui bahwa sebenarnya ada dua fungsi sakelar yang berbeda. Ini bukan fungsi umum tetapi Anda harus memikirkannya sebagai salah satu
switch.numeric
atauswitch.character
. Jika argumen pertama Anda adalah 'faktor' R, Anda mendapatkanswitch.numeric
perilaku, yang mungkin menyebabkan masalah, karena kebanyakan orang melihat faktor ditampilkan sebagai karakter dan membuat asumsi yang salah bahwa semua fungsi akan memprosesnya seperti itu.sumber
Anda dapat menggunakan kode ulang dari paket mobil:
library(ggplot2) #get data library(car) daimons$new_var <- recode(diamonds$clarity , "'I1' = 'low';'SI2' = 'low';else = 'high';")[1:10]
sumber
sos::findFn("recode")
temuandoBy::recodeVar
,epicalc::recode
,memisc::recode
, tapi saya belum melihat mereka secara rinci ...saya tidak suka semua ini, mereka tidak jelas bagi pembaca atau pengguna potensial. Saya hanya menggunakan fungsi anonim, sintaksnya tidak semulus pernyataan kasus, tetapi evaluasinya mirip dengan pernyataan kasus dan tidak terlalu menyakitkan. ini juga mengasumsikan Anda mengevaluasinya di tempat variabel Anda ditentukan.
result <- ( function() { if (x==10 | y< 5) return('foo') if (x==11 & y== 5) return('bar') })()
semua itu () diperlukan untuk menyertakan dan mengevaluasi fungsi anonim.
sumber
result <- (if (x==10 | y< 5) 'foo' else if (x==11 & y== 5) 'bar' )
. 2) Ini hanya berfungsi jikax
dany
merupakan skalar; untuk vektor, seperti pada pertanyaan awal,ifelse
pernyataan bertingkat akan diperlukan.Saya menggunakan dalam kasus-kasus yang Anda maksud
switch()
. Ini terlihat seperti pernyataan kontrol tetapi sebenarnya, ini adalah fungsi. Ekspresi dievaluasi dan berdasarkan nilai ini, item yang sesuai dalam daftar dikembalikan.Berikut ini adalah contoh string sederhana yang memecahkan masalah Anda untuk menciutkan kategori lama ke kategori baru.
newCat <- switch(EXPR = category, cat1 = catX, cat2 = catX, cat3 = catY, cat4 = catY, cat5 = catZ, cat6 = catZ, "not available")
sumber
Jika Anda ingin memiliki sintaks seperti sql, Anda dapat menggunakan
sqldf
paket. Tfungsi yang akan digunakan juga namasqldf
dan sintaksnya adalah sebagai berikutsqldf(<your query in quotation marks>)
sumber
Pernyataan kasus sebenarnya mungkin bukan pendekatan yang tepat di sini. Jika ini adalah sebuah faktor, yang kemungkinan besar terjadi, atur saja tingkat faktornya dengan tepat.
Katakanlah Anda memiliki faktor dengan huruf A sampai E, seperti ini.
> a <- factor(rep(LETTERS[1:5],2)) > a [1] A B C D E A B C D E Levels: A B C D E
Untuk menggabungkan level B dan C dan menamakannya BC, cukup ubah nama level tersebut menjadi BC.
> levels(a) <- c("A","BC","BC","D","E") > a [1] A BC BC D E A BC BC D E Levels: A BC D E
Hasilnya sesuai keinginan.
sumber
Mencampur
plyr::mutate
dandplyr::case_when
bekerja untuk saya dan dapat dibaca.iris %>% plyr::mutate(coolness = dplyr::case_when(Species == "setosa" ~ "not cool", Species == "versicolor" ~ "not cool", Species == "virginica" ~ "super awesome", TRUE ~ "undetermined" )) -> testIris head(testIris) levels(testIris$coolness) ## NULL testIris$coolness <- as.factor(testIris$coolness) levels(testIris$coolness) ## ok now testIris[97:103,4:6]
Poin bonus jika kolom dapat keluar dari mutasi sebagai faktor, bukan karakter! Baris terakhir dari pernyataan case_when, yang menangkap semua baris yang tidak cocok sangatlah penting.
Petal.Width Species coolness 97 1.3 versicolor not cool 98 1.3 versicolor not cool 99 1.1 versicolor not cool 100 1.3 versicolor not cool 101 2.5 virginica super awesome 102 1.9 virginica super awesome 103 2.1 virginica super awesome
sumber
Anda dapat menggunakan
base
fungsi tersebutmerge
untuk tugas pemetaan ulang gaya huruf:df <- data.frame(name = c('cow','pig','eagle','pigeon','cow','eagle'), stringsAsFactors = FALSE) mapping <- data.frame( name=c('cow','pig','eagle','pigeon'), category=c('mammal','mammal','bird','bird') ) merge(df,mapping) # name category # 1 cow mammal # 2 cow mammal # 3 eagle bird # 4 eagle bird # 5 pig mammal # 6 pigeon bird
sumber
Pada data.table v1.13.0 Anda dapat menggunakan fungsi
fcase()
(kasus cepat) untuk melakukanCASE
operasi seperti SQL (juga mirip dengandplyr::case_when()
):require(data.table) dt <- data.table(name = c('cow','pig','eagle','pigeon','cow','eagle')) dt[ , category := fcase(name %in% c('cow', 'pig'), 'mammal', name %in% c('eagle', 'pigeon'), 'bird') ]
sumber