2012-12-31 65 views
5

我有一個數據框z,我想基於兩個舊列z的值創建新列。下面是該過程:在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 

#產生列q,其等於列的值t倍4如果x=3和用於x其他值,它等於t列的值。

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

但是,我的問題是,我想申請多個條件:

例如,我想是這樣的:

(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 

我如何使用第二輸出循環或其他方法?

+1

另外,最好使用'ifelse'而不是'for'循環。而不是'(for i in 1:length(x))y [i] < - if ... else ...'你可以做'y < - ifelse(邏輯,真,假)' –

+1

@Señor:根據你的建議,我發佈了自己問題的答案。謝謝! – Metrics

回答

3

生成一個乘數向量:

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

,這是你的新列:

> 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 

是否有z$x負值這是行不通的。

被修改

下面是上述的概括,其中的功能被用於生成乘法器矢量。實際上,我們基於參數創建一個函數。

我們要改變以下值:

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

否則默認設置爲1時服用。

這裏是產生所需功能的函數:

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 
    } 
} 

下面是我們如何使用它:

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

g <- f(1, x, y) 

g是我們想要的功能。應該清楚的是,任何映射都可以通過參數xy提供給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 

應該清楚這隻適用於整數值。

+0

非常感謝馬修。 – Metrics

3

基於閱兵式的建議:

> 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

通過由遞歸構建一個嵌套ifelse功能,你可以得到迄今提出兩種解決方案的好處:ifelse速度快,可與任何類型的數據工作,而@馬修的解決方案更實用,但限於整數並可能很慢。

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)) 
} 

請注意decode函數是如何在SQL函數後命名的。我想這樣的功能做了它對基礎R包...這裏有兩個例子說明它的用法:

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 

爲了您的具體問題:

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

非常好。我正在考慮像這樣做一個遞歸函數定義,但留下了「以後」可能永遠不會。 –

+0

更好的是,如果你推廣這一點,以便「搜索」可以是目標向量列表(例如'search = list(c(「apple」,「orange」),c(「carrot」,「potato」))替換爲c(「水果」,「根」)(甚至是「search = list(fruit = c(」apple「,」orange「),root = c(」carrot「,」potato「))',儘管這隻適用於字符串替換)。我認爲'car'包有一個'recode'的因素,但它是基於字符串和笨重的...... –

1

您還可以使用匹配做這個。我傾向於同時在散點圖分配像山坳,PCH和CEX參數來分這個使用了大量

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

這裏只有一個ifelse命令一個簡單的解決方案:

計算t乘數:

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

完整的命令:

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

我真的很喜歡回答「dinre」張貼到flodel的博客:

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

有警告有關仔細閱讀幫助頁面switch整數參數。

2

你可以用一條線

  • 其中映射是相當清楚的代碼
  • 沒有輔助功能來讀取(OK,一個匿名函數做在

    • 基礎R
    • 方法使用底片
    • 方法適用於任何原子矢量(真實,字符)

    這樣的:

    > 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

    下面是R代表特徵向量(未經測試與因素)的SQL decode一個版本的工作就像SQL版本。即它接受任意數量的目標/替換對,並且可選的最後一個參數作爲默認值(注意,默認值不會覆蓋NAs)。

    我可以看到它與dplyrmutate操作相結合非常有用。

    > 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 
    

    下面是我使用的,具有依據的代碼,我會跟上這裏(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) 
    
    } 
    
    相關問題