Veri çerçevesindeki bir değeri koşullu ("if") ifadesine göre değiştirin


122

Aşağıda kodlanmış R veri çerçevesinde, B görünen tüm zamanları ile değiştirmek istiyorum b.

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12])
colnames(junk) <- c("nm", "val")

bu şunları sağlar:

   nm val
1   A   a
2   B   b
3   C   c
4   D   d
5   A   e
6   B   f
7   C   g
8   D   h
9   A   i
10  B   j
11  C   k
12  D   l

İlk denemem şu şekilde a forve ififadelerini kullanmaktı :

for(i in junk$nm) if(i %in% "B") junk$nm <- "b"

Ben eminim ama, TÜM değerleri bu yerini alır görebilirsiniz junk$nmile b. Bunun neden bunu yaptığını anlayabiliyorum ama onu yalnızca orijinal değerin olduğu önemsiz $ nm durumlarının yerini alacak gibi görünmüyorum B.

NOT: Problemi çözmeyi başardım, gsubancak UR'yi öğrenmek için hala orijinal yaklaşımımı nasıl çalıştıracağımı bilmek istiyorum (eğer mümkünse)


1
orijinal data.frame yapısına stringsAsFactors = FALSE eklemek isteyebilirsiniz.
jimmyb

@jimmyb Neden? Faktörler kullanışlıdır ve R'nin modelleme kodunun çoğu ile modelleme yapılıyorsa gereklidir. Bununla başa çıkmanın doğru yolu, verilerin bir faktör olduğunu kabul etmektir. Bu dönüşümü istemiyorsanız / buna ihtiyacınız yoksa, söylediğinizi yapabilirsiniz. Faktörü istiyorsanız, @ Kenny'nin gerçekleştirmek istediği manipülasyonu yapmanın kolay yolları vardır.
Gavin Simpson

1
Öyleyse, faktörler performans nedeniyle daha popülerdi, ancak artık dizeler değişmez ve karma hale getirildiğinden, temel R işlevselliğinin çoğu onları (uyarılarla da olsa) doğrudan dönüştürdüğü için faktörlerin değeri daha az açıktır. Bence faktörler, insanların R kodunda bulduğum önemli sayıda hataya neden oluyor.
jimmyb

Yanıtlar:


217

Nm'yi karakterlere dönüştürmek daha kolaydır ve ardından değişikliği yapın:

junk$nm <- as.character(junk$nm)
junk$nm[junk$nm == "B"] <- "b"

DÜZENLEME: Ve gerçekten de nm'yi faktör olarak tutmanız gerekiyorsa, sonuna şunu ekleyin:

junk$nm <- as.factor(junk$nm)

4
as.character (), faktörlerle çalışırken hayatı çok daha kolaylaştırır. +1
Brandon Bertelsen

4
ya birden çok sütununuz varsa?
geodex

43

değerleri değiştirmenin başka bir kullanışlı yolu

library(plyr)
junk$nm <- revalue(junk$nm, c("B"="b"))

25

Kısa cevap:

junk$nm[junk$nm %in% "B"] <- "b"

R Giriş bölümündeki İndeks vektörlerine bir göz atın (henüz okumadıysanız).


DÜZENLE. Yorumlarda belirtildiği gibi, bu çözüm karakter vektörleri için işe yarıyor, bu nedenle verilerinizde başarısız oluyor.

Faktör için en iyi yol, seviyeyi değiştirmektir:

levels(junk$nm)[levels(junk$nm)=="B"] <- "b"

Kısa ek:% in% kullanımı yalnızca sağ tarafta bir setiniz varsa gerçekten yardımcı olur c("B","C"). Yapmak junk$nm[junk$nm == "B"]daha iyi bir yoldur.
Thilo

1
Oh, başka, önemli bir ekleme: Böyle yapmak, önce faktör düzeyini bnm faktörüne eklemeyi gerektirir . diliop'un sürümü, faktörlerle değil karakterlerle çalışmak istiyorsanız aslında daha iyidir. (Daima değişkenlerinizin sahip olduğu türü düşünün!)
Thilo

@ Kenny tarafından oluşturulan veriler üzerinde çalışmaz çünkü veriler faktörlerdir. Bir adımı unuttunuz mu veya karakterleri faktörlere dönüştürmeyi durdurmak için genel ayarınız var mı?
Gavin Simpson

4
@Thilo arasında önemli farklardan biri %in%ve ==bir NAtaşıma: c(1,2,NA)==1verir TRUE, FALSE, NAama c(1,2,NA) %in% 1verir TRUE, FALSE, FALSE. Ve evet, bunun işe
Marek

20

Gösterdiğiniz veriler faktör olduğundan, işleri biraz karmaşıklaştırır. @ diliop'un Cevabı soruna nmbir karakter değişkenine dönüştürerek yaklaşır . Orijinal faktörlere geri dönmek için daha ileri bir adım gereklidir.

Bir alternatif, yerinde faktör seviyelerini manipüle etmektir.

> lev <- with(junk, levels(nm))
> lev[lev == "B"] <- "b"
> junk2 <- within(junk, levels(nm) <- lev)
> junk2
   nm val
1   A   a
2   b   b
3   C   c
4   D   d
5   A   e
6   b   f
7   C   g
8   D   h
9   A   i
10  b   j
11  C   k
12  D   l

Bu oldukça basit ve sık sık bunun için bir değiştirme işlevi olduğunu unutuyorum levels().

Düzenleme: @Seth tarafından yorumlarda belirtildiği gibi, bu, netlik kaybı olmadan tek satırda yapılabilir:

within(junk, levels(nm)[levels(nm) == "B"] <- "b")

6
Güzel. Yerine koyma işlevini bilmiyordum levels(). Tek astara ne dersin junk <- within(junk, levels(nm)[levels(nm)=="B"] <- "b")?

Ama iki kere çağırıyorsun :)
Marek

2
@Marek tokat atıyor Sadece yatma vaktini geçmişken SO hakkındaki yorumlara yanıt verilmemesi gerektiğini gösteriyor. Tekrar deneyelim ...
Gavin Simpson

@Seth Indeed - güzel. Adımları neden ayırdığımdan emin değil misiniz? Belki açıklama için ...
Gavin Simpson

11

Bunu tek bir komutta yapmanın en kolay yolu, komutu kullanmaktır whichve bunu yaparak faktörleri karaktere dönüştürmek zorunda kalmamaktır:

junk$nm[which(junk$nm=="B")]<-"b"

5

İçinde bir faktör değişkeni oluşturdunuz, nmbu nedenle ya bundan kaçınmanız ya da faktör özelliklerine ek bir seviye eklemeniz gerekir. <-Data.frame () argümanlarında kullanmaktan da kaçınmalısınız.

Seçenek 1:

junk <- data.frame(x = rep(LETTERS[1:4], 3), y =letters[1:12], stringsAsFactors=FALSE)
junk$nm[junk$nm == "B"] <- "b"

Seçenek 2:

levels(junk$nm) <- c(levels(junk$nm), "b")
junk$nm[junk$nm == "B"] <- "b"
junk

@DWin, sorunla ilgili görüşleriniz ve değişken türünü dikkate alma ihtiyacınız için teşekkür ederiz. @ Diliop'un cevabını ilk çalışan cevap olduğu için kabul ettim. <- vs = üzerinde çok fazla sorun olduğunu biliyorum ama (kısaca cevaplanabiliyorsa) neden = ile birlikte kullanılmalı data.frame?
DQdlM

Ekleyebilir gerekmez badildir düzeyini değiştirmek, bir düzey olarak Biçin b.
Gavin Simpson

@KennyPeanuts: Sütun adı bir sorundur, Bakın a <- data.frame(x<-1:10). Sütun adı xdağınık değil x....1.10. Data.frame kullanmak daha iyidir (x = 1: 10). O zaman sütun adınızın ne olduğunu bilirsiniz.
IRTFM

@Gavin: Değiştirmek yerine eklemek daha kolay ve onu bir faktör haline getirmemek daha da kolay.
IRTFM

@Dwin Daha Kolay? Katılmıyorum - basit bir şey için Cevabıma bakın. Örneğin predict(), yeni verilerdeki faktör seviyeleri modele uymak için kullanılanlarla uyuşmadığında şikayet edecek olan modellemede seviye eklemek sizi yakalayabilir . Verileri istediğiniz gibi biçimlendirmek için kısa yollara güvenmek yerine uzun vadede daha temiz. Bunu bir faktör haline getirmemenin daha kolay olabileceğine katılıyorum, ancak zaten birse veya bazı modelleme alıştırmaları için olması gerekiyorsa ...
Gavin Simpson

1

Karakter değişkenleriyle çalışıyorsanız ( stringsAsFactorsburada bunun yanlış olduğuna dikkat edin ), değiştirmeyi kullanabilirsiniz:

junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12], stringsAsFactors = FALSE)
colnames(junk) <- c("nm", "val")

junk$nm <- replace(junk$nm, junk$nm == "B", "b")
junk
#    nm val
# 1   A   a
# 2   b   b
# 3   C   c
# 4   D   d
# ...

0
stata.replace<-function(data,replacevar,replacevalue,ifs) {
  ifs=parse(text=ifs)
  yy=as.numeric(eval(ifs,data,parent.frame()))
  x=sum(yy)
  data=cbind(data,yy)
  data[yy==1,replacevar]=replacevalue
  message=noquote(paste0(x, " replacement are made"))
  print(message)
  return(data[,1:(ncol(data)-1)])
}

Aşağıdaki satırı kullanarak bu işlevi çağırın.

d=stata.replace(d,"under20",1,"age<20")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.