2012-12-31 16 views
5

Mam ramkę danych z i chcę utworzyć nową kolumnę na podstawie wartości dwóch starych kolumn z z. Następujący sposób:generowanie wartości kolumn z wieloma warunkami w R

>z<-cbind(x=1:10,y=11:20,t=21:30) 
> z<-as.data.frame(z) 
>z 
    x y t 
1 1 11 21 
2 2 12 22 
3 3 13 23 
4 4 14 24 
5 5 15 25 
6 6 16 26 
7 7 17 27 
8 8 18 28 
9 9 19 29 
10 10 20 30 

# generowania kolumnę q, która jest równa wartości kolumny t razy 4 jeśli x=3 i innych wartości x jest równa wartości kolumny t.

for (i in 1:nrow(z)){ 
    z$q[i]=if (z$x[i]==4) 4*z$t[i] else z$t[i]} 

Ale mój problem jest, że chcę, aby zastosować wiele warunków:

Na przykład, chcę, żeby coś takiego:

(If x=2, q=t*2; x=4, q=t*4; x=7, q=t*3; for other it is equal to t) 

> z 
    x y t q 
1 1 11 21 21 
2 2 12 22 44 
3 3 13 23 23 
4 4 14 24 96 
5 5 15 25 25 
6 6 16 26 26 
7 7 17 27 81 
8 8 18 28 28 
9 9 19 29 29 
10 10 20 30 30 

Jak mogę dostać drugie wyjście używając pętle lub jakakolwiek inna metoda?

+1

Również lepiej użyć 'ifelse' niż pętli' for', którą miałeś. Zamiast '(dla i in 1: length (x)) y [i] <- if ... else ...' możesz po prostu zrobić 'y <- ifelse (logiczne, prawda, fałsz)' –

+1

@ Señor: Na podstawie Twojej sugestii wysłałem odpowiedź na moje własne pytanie. Dzięki! – Metrics

Odpowiedz

3

Generowanie multipler Vector:

tt <- rep(1, max(z$x)) 
tt[2] <- 2 
tt[4] <- 4 
tt[7] <- 3 

I tu jest twoja nowa kolumna:

> z$t * tt[z$x] 
[1] 21 44 23 96 25 26 81 28 29 30 

> z$q <- z$t * tt[z$x] 
> z 
    x y t q 
1 1 11 21 21 
2 2 12 22 44 
3 3 13 23 23 
4 4 14 24 96 
5 5 15 25 25 
6 6 16 26 26 
7 7 17 27 81 
8 8 18 28 28 
9 9 19 29 29 
10 10 20 30 30 

To nie będzie działać, jeśli istnieją wartości ujemne w z$x.

Zmieniano

Oto uogólnienie powyżej, gdy funkcja jest stosowana do wytworzenia wektora mnożnika. W rzeczywistości tworzymy funkcję opartą na parametrach.

Chcemy przekształcić następujące wartości:

2 -> 2 
4 -> 4 
7 -> 3 

przeciwnym wypadku domyślna 1 jest podjąć.

Oto funkcja, która generuje żądaną funkcję:

f <- function(default, x, y) { 
    x.min <- min(x) 
    x.max <- max(x) 
    y.vals <- rep(default, x.max-x.min+1) 
    y.vals[x-x.min+1] <- y 

    function(z) { 
    result <- rep(default, length(z)) 
    tmp <- z>=x.min & z<=x.max 
    result[tmp] <- y.vals[z[tmp]-x.min+1] 
    result 
    } 
} 

Oto jak go używać:

x <- c(2,4,7) 
y <- c(2,4,3) 

g <- f(1, x, y) 

g to funkcja chcemy. Powinno być jasne, że każde odwzorowanie może być dostarczone za pomocą parametrów x i y do f.

g(z$x) 
## [1] 1 2 1 4 1 1 3 1 1 1 

g(z$x)*z$t 
## [1] 21 44 23 96 25 26 81 28 29 30 

Powinno być jasne, że działa tylko dla wartości całkowitych.

+0

Wielkie dzięki Matthew. – Metrics

3

oparciu o sugestię Señor:

> z$q <- ifelse(z$x == 2, z$t * 2, 
     ifelse(z$x == 4, z$t * 4, 
     ifelse(z$x == 7, z$t * 3, 
          z$t * 1))) 
> z 
    x y t q 
1 1 11 21 21 
2 2 12 22 44 
3 3 13 23 23 
4 4 14 24 96 
5 5 15 25 25 
6 6 16 26 26 
7 7 17 27 81 
8 8 18 28 28 
9 9 19 29 29 
10 10 20 30 30 
10

budując zagnieżdżona ifelse funkcjonalny przez rekursji, można uzyskać korzyści z obu rozwiązań oferowanych do tej pory: ifelse jest szybka i może pracować z dowolnym typem danych , podczas gdy rozwiązanie @ Matthew jest bardziej funkcjonalne, ale ograniczone do liczb całkowitych i potencjalnie wolne.

decode <- function(x, search, replace, default = NULL) { 

    # build a nested ifelse function by recursion 
    decode.fun <- function(search, replace, default = NULL) 
     if (length(search) == 0) { 
     function(x) if (is.null(default)) x else rep(default, length(x)) 
     } else { 
     function(x) ifelse(x == search[1], replace[1], 
              decode.fun(tail(search, -1), 
                 tail(replace, -1), 
                 default)(x)) 
     } 

    return(decode.fun(search, replace, default)(x)) 
} 

Uwaga: nazwa funkcji decode pochodzi od funkcji SQL. Życzę funkcja jak to uczyniło go do pakietu podstawowego R ... Oto kilka przykładów ilustrujących jego wykorzystania:

decode(x = 1:5, search = 3, replace = -1) 
# [1] 1 2 -1 4 5 
decode(x = 1:5, search = c(2, 4), replace = c(20, 40), default = 3) 
# [1] 3 20 3 40 3 

dla konkretnego problemu:

transform(z, q = decode(x, search = c(2,4,7), replace = c(2,4,3), default = 1) * t) 

# x y t q 
# 1 1 11 21 21 
# 2 2 12 22 44 
# 3 3 13 23 23 
# 4 4 14 24 96 
# 5 5 15 25 25 
# 6 6 16 26 26 
# 7 7 17 27 81 
# 8 8 18 28 28 
# 9 9 19 29 29 
# 10 10 20 30 30 
+0

Bardzo ładne. Myślałem o zrobieniu takiej definicji funkcji rekursywnej, ale zostawiłem to dla "późniejszego", co mogło nigdy nie być. –

+0

Jeszcze ładniej, jeśli uogólnisz to, aby "szukaj" mogło być listą wektorów celów (np. 'Search = list (c (" jabłko "," pomarańczowy "), c (" marchewka "," ziemniak ")), replace = c ("fruit", "root") '(lub nawet' search = list (fruit = c ("apple", "orange"), root = c ("carrot", "potato")) ', chociaż działa tylko w przypadku zamiany ciągów znaków). Myślę, że pakiet 'car' ma' recode' dla czynników, ale jest oparty na łańcuchach i clunky ... –

1

Można również wykorzystać mecz Zrób to. I mają tendencję do używania tego dużo podczas przypisywania parametrów jak COL PCH i CEX do punktów w rozrzutu

searchfor<-c(2,4,7) 
replacewith<-c(2,4,3) 

# generate multiplier column 
# q could also be an existing vector where you want to replace certain entries 
q<-rep(1,nrow(z)) 
# 
id<-match(z$x,searchfor) 
id<-replacewith[id] 
# Apply the matches to q 
q[!is.na(id)]<-id[!is.na(id)] 
# apply to t 
z$q<-q*z$t 
3

Oto proste rozwiązanie z jednym ifelse polecenia:

Oblicz mnożnik t:

ifelse(z$x == 7, 3, z$x^(z$x %in% c(2, 4))) 

kompletny polecenie:

transform(z, q = t * ifelse(x == 7, 3, x^(x %in% c(2, 4)))) 

    x y t q 
1 1 11 21 21 
2 2 12 22 44 
3 3 13 23 23 
4 4 14 24 96 
5 5 15 25 25 
6 6 16 26 26 
7 7 17 27 81 
8 8 18 28 28 
9 9 19 29 29 
10 10 20 30 30 
2

Bardzo podobała mi się odpowiedź „dinre” Zamieszczone na flodel blog:

for (i in 1:length(data_Array)){ 
data_Array[i] <- switch(data_Array[i], banana="apple", orange="pineapple", "fig") 
} 

z ostrzeżeniami o czytaniu stronę pomocy dla switch uważnie argumentów całkowitych.

2

Można to zrobić w

  • bazowej R
  • z jednej linii
  • , w którym mapowanie jest całkiem jasne do odczytania w kodzie
  • żadne funkcje pomocnicze (ok, anonimowa funkcja)
  • podejście działa z negatywami
  • podejście działa z dowolnym wektorem atomowym (reale, znaki)

tak:

> transform(z,q=t*sapply(as.character(x),function(x) switch(x,"2"=2,"4"=4,"7"=3,1))) 
    x y t q 
1 1 11 21 21 
2 2 12 22 44 
3 3 13 23 23 
4 4 14 24 96 
5 5 15 25 25 
6 6 16 26 26 
7 7 17 27 81 
8 8 18 28 28 
9 9 19 29 29 
10 10 20 30 30 
1

Oto wersja z SQL decode w R dla wektorów znak (nietestowanego z czynników), który działa podobnie jak w wersji SQL. tj. pobiera dowolną liczbę par docelowych/zastępczych i opcjonalny ostatni argument, który działa jako wartość domyślna (zauważ, że domyślne nie zastąpią NA).

widzę, że był całkiem przydatna w połączeniu z mutate pracy dplyr „s.

> x <- c("apple","apple","orange","pear","pear",NA) 

> decode(x, apple, banana) 
[1] "banana" "banana" "orange" "pear" "pear" NA  

> decode(x, apple, banana, fruit) 
[1] "banana" "banana" "fruit" "fruit" "fruit" NA  

> decode(x, apple, banana, pear, passionfruit) 
[1] "banana"  "banana"  "orange"  "passionfruit" "passionfruit" NA    

> decode(x, apple, banana, pear, passionfruit, fruit) 
[1] "banana"  "banana"  "fruit"  "passionfruit" "passionfruit" NA 

Oto kod używam, z GIST będę na bieżąco tutaj (link).

decode <- function(x, ...) { 

    args <- as.character((eval(substitute(alist(...)))) 

    replacements <- args[1:length(args) %% 2 == 0] 
    targets  <- args[1:length(args) %% 2 == 1][1:length(replacements)] 

    if(length(args) %% 2 == 1) 
    x[! x %in% targets & ! is.na(x)] <- tail(args,1) 

    for(i in 1:length(targets)) 
    x <- ifelse(x == targets[i], replacements[i], x) 

    return(x) 

} 
Powiązane problemy