2015-02-18 19 views
11

Tôi không thể sử dụng công tắc bên trong của mutate vì nó trả về toàn bộ véc tơ thay vì chỉ là hàng. Là một hack, tôi đang sử dụng:Có chức năng nào giống như công tắc hoạt động bên trong dplyr :: mutate không?

pick <- function(x, v1, v2, v3, v4) { 
    ifelse(x == 1, v1, 
      ifelse(x == 2, v2, 
        ifelse(x == 3, v3, 
         ifelse(x == 4, v4, NA)))) 
} 

Điều này hoạt động bên trong mutate và bây giờ là vì tôi thường chọn trong số 4 điều, nhưng điều đó có thể thay đổi. Bạn có thể giới thiệu một giải pháp thay thế không?

Ví dụ:

library(dplyr) 
df.faithful <- tbl_df(faithful) 
df.faithful$x <- sample(1:4, 272, rep=TRUE) 
df.faithful$y1 <- rnorm(n=272, mean=7, sd=2) 
df.faithful$y2 <- rnorm(n=272, mean=5, sd=2) 
df.faithful$y3 <- rnorm(n=272, mean=7, sd=1) 
df.faithful$y4 <- rnorm(n=272, mean=5, sd=1) 

Sử dụng pick:

mutate(df.faithful, y = pick(x, y1, y2, y3, y4)) 
Source: local data frame [272 x 8] 

    eruptions waiting x  y1  y2  y3  y4  y 
1  3.600  79 1 8.439092 5.7753006 8.319372 5.078558 8.439092 
2  1.800  54 2 13.515956 6.1971512 6.343157 4.962349 6.197151 
3  3.333  74 4 7.693941 6.8973365 5.406684 5.425404 5.425404 
4  2.283  62 4 12.595852 6.9953995 7.864423 3.730967 3.730967 
5  4.533  85 3 11.952922 5.1512987 9.177687 5.511899 9.177687 
6  2.883  55 3 7.881350 1.0289711 6.304004 3.554056 6.304004 
7  4.700  88 4 8.636709 6.3046198 6.788619 5.748269 5.748269 
8  3.600  85 1 8.027371 6.3535056 7.152698 7.034976 8.027371 
9  1.950  51 1 5.863370 0.1707758 5.750440 5.058107 5.863370 
10  4.350  85 1 7.761653 6.2176610 8.348378 1.861112 7.761653 
..  ...  ... .  ...  ...  ...  ...  ... 

Chúng tôi thấy rằng tôi sao chép giá trị từ y1 vào y nếu x == 1, và vân vân. Đây là những gì tôi đang tìm kiếm để làm, nhưng muốn có thể làm điều đó, cho dù tôi có một danh sách 4 hoặc 400 cột.

Cố gắng sử dụng switch:

mutate(df.faithful, y = switch(x, y1, y2, y3, 4)) 

Error in switch(c(1L, 2L, 4L, 4L, 3L, 3L, 4L, 1L, 1L, 1L, 4L, 3L, 1L, : 
EXPR must be a length 1 vector 

Cố gắng sử dụng list:

mutate(df.faithful, y = list(y1, y2, y3, y4)[[x]]) 
Error in list(c(8.43909205142925, 13.5159559591257, 7.69394050059568, : 
recursive indexing failed at level 2 

Cố gắng sử dụng c:

mutate(df.faithful, y = c(y1, y2, y3, y4)[x]) 
Source: local data frame [272 x 8] 

    eruptions waiting x  y1  y2  y3  y4   y 
1  3.600  79 1 8.439092 5.7753006 8.319372 5.078558 8.439092 
2  1.800  54 2 13.515956 6.1971512 6.343157 4.962349 13.515956 
3  3.333  74 4 7.693941 6.8973365 5.406684 5.425404 12.595852 
4  2.283  62 4 12.595852 6.9953995 7.864423 3.730967 12.595852 
5  4.533  85 3 11.952922 5.1512987 9.177687 5.511899 7.693941 
6  2.883  55 3 7.881350 1.0289711 6.304004 3.554056 7.693941 
7  4.700  88 4 8.636709 6.3046198 6.788619 5.748269 12.595852 
8  3.600  85 1 8.027371 6.3535056 7.152698 7.034976 8.439092 
9  1.950  51 1 5.863370 0.1707758 5.750440 5.058107 8.439092 
10  4.350  85 1 7.761653 6.2176610 8.348378 1.861112 8.439092 
..  ...  ... .  ...  ...  ...  ...  ... 

Không có lỗi được sản xuất, nhưng hành vi đó không phải là như dự định.

+3

Đó là một câu hỏi thú vị nhưng sẽ tốt hơn nếu bạn có thể làm cho nó có thể tái sản xuất với một ví dụ làm việc tối thiểu. Trong biểu mẫu hiện tại, có vẻ như bạn có thể thử 'danh sách (v1, v2, v3, v4) [[x]]' thay thế. –

+0

Nhận xét hợp lệ. Bạn có thể nói những gì tôi yêu cầu bây giờ không? – wdkrnls

+1

Sử dụng 'd%>% biến đổi (y = cbind (y1, y2, y3, y4) [cbind (1: n(), x)])' hoặc 'd $ y <- as.data.frame (d) [cbind (1: nrow (d), d $ x + 3)] ' –

Trả lời

17

Eons quá muộn cho OP, nhưng trong trường hợp này xuất hiện trong một tìm kiếm ...

dplyr v0.5 có recode(), một phiên bản vectorized của switch(), vì vậy

data_frame(
    x = sample(1:4, 10, replace=TRUE), 
    y1 = rnorm(n=10, mean=7, sd=2), 
    y2 = rnorm(n=10, mean=5, sd=2), 
    y3 = rnorm(n=10, mean=7, sd=1), 
    y4 = rnorm(n=10, mean=5, sd=1) 
) %>% 
mutate(y = recode(x,y1,y2,y3,y4)) 

sản xuất, như dự kiến:

# A tibble: 10 x 6 
     x  y1  y2  y3  y4  y 
    <int>  <dbl> <dbl> <dbl> <dbl> <dbl> 
1  2 6.950106 6.986780 7.826778 6.317968 6.986780 
2  1 5.776381 7.706869 7.982543 5.048649 5.776381 
3  2 7.315477 2.213855 6.079149 6.070598 2.213855 
4  3 7.461220 5.100436 7.085912 4.440829 7.085912 
5  3 5.780493 4.562824 8.311047 5.612913 8.311047 
6  3 5.373197 7.657016 7.049352 4.470906 7.049352 
7  2 6.604175 9.905151 8.359549 6.430572 9.905151 
8  3 11.363914 4.721148 7.670825 5.317243 7.670825 
9  3 10.123626 7.140874 6.718351 5.508875 6.718351 
10  4 5.407502 4.650987 5.845482 4.797659 4.797659 

(Cũng hoạt động với tên args, bao gồm nhân vật và yếu tố x.)

2

Bạn có thể thay đổi chức năng của bạn trên đường đi này:

map <- data.frame(i=1:2,v=10:11) 
# i v 
# 1 1 10 
# 2 2 11 

set.seed(1) 
x <- sample(1:3,10,rep=T) 
# [1] 1 2 2 3 1 3 3 2 2 1 

i <- match(x,map$i) 
ifelse(is.na(i),x,map$v[i]) 
# [1] 10 11 11 3 10 3 3 11 11 10 

Ý tưởng là để giữ cho các giá trị mà bạn đang tìm kiếm và thay thế các giá trị trong một khung dữ liệu riêng biệt map, và sau đó sử dụng để phù hợp với matchxmap.

[Cập nhật]

Bạn có thể quấn lên giải pháp này thành một chức năng có thể được sử dụng trong mutate:

multipleReplace <- function(x, what, by) { 
    stopifnot(length(what)==length(by))    
    ind <- match(x, what) 
    ifelse(is.na(ind),x,by[ind]) 
} 

# Create a sample data set 
d <- structure(list(x = c(1L, 2L, 2L, 3L, 1L, 3L, 3L, 2L, 2L, 1L), y = c(1L, 2L, 2L, 3L, 3L, 1L, 3L, 2L, 2L, 1L)), .Names = c("x", "y"), row.names = c(NA, -10L), class = "data.frame") 

d %>% 
    mutate(z = multipleReplace(x, what=c(1,3), by=c(101,103))) 
# x y z 
# 1 1 1 101 
# 2 2 2 2 
# 3 2 2 2 
# 4 3 3 103 
# 5 1 3 101 
# 6 3 1 103 
# 7 3 3 103 
# 8 2 2 2 
# 9 2 2 2 
# 10 1 1 101 
2

Do hoạt động của mỗi giá trị của x. Đây là phiên bản data.table, tôi giả sử smth tương tự có thể được thực hiện trong dplyr:

library(data.table) 

dt = data.table(x = c(1,1,2,2), a = 1:4, b = 4:7) 

dt[, newcol := switch(as.character(x), '1' = a, '2' = b, NA), by = x] 
dt 
# x a b newcol 
#1: 1 1 4  1 
#2: 1 2 5  2 
#3: 2 3 6  6 
#4: 2 4 7  7 
+0

@DavidArenburg Tôi quên chuyển đổi thành ký tự (đó là điều làm cho' switch' care), xem chỉnh sửa – eddi

0

Một thay thế (tham gia nhiều hơn) tuyến đường liên quan đến việc sử dụng tidyr:

df %>% 
    mutate(row = row_number()) %>% 
    gather(n, y, y1:y4) %>% 
    mutate(n = as.integer(str_extract(n, "[0-9]+"))) %>% 
    filter(x == n) %>% 
    arrange(row) %>% 
    select(-c(row, n)) 
2

Dưới đây là một cách khác để sử dụng data.table. Ý tưởng là để về cơ bản tạo ra một chìa khóa data.table với các kết hợp và sau đó thực hiện một tham gia, như sau:

tôi sẽ sử dụng các data.table từ câu trả lời @ Eddi của.

require(data.table) 
key = data.table(x = 1:2, col = c("a", "b")) 

setkey(dt, x) 
dt[key, new_col := get(i.col), by=.EACHI] 
# x a b new_col 
# 1: 1 1 4  1 
# 2: 1 2 5  2 
# 3: 2 3 6  6 
# 4: 2 4 7  7 

Các tham gia được thực hiện trên cột x. Đối với mỗi hàng khóa, các hàng phù hợp tương ứng trong số dt được tìm thấy. Ví dụ: x = 1 từ khóa phù hợp với hàng và của dt. Và trên các hàng đó, chúng tôi truy cập cột được lưu trữ trong khóa củacol, là "a". get("a") trả về giá trị của cột a cho các hàng phù hợp đó, là và . Hi vọng điêu nay co ich.

by=.EACHI đảm bảo rằng biểu thức new_col := get(i.col) được đánh giá cho mỗi hàng trong key. Bạn có thể tìm hiểu thêm về nó here.

+1

Phương pháp nối dường như tốt nhất với tôi (+ 1) - nhưng thật ngạc nhiên khi thấy điều này được trình bày dưới dạng câu trả lời cụ thể 'data.table'. Có thể được thực hiện với 'dplyr :: left_join' hoặc đơn giản là' match' hoặc 'merge'. – Gregor

+0

Tôi thực sự không hiểu ý kiến ​​của bạn dưới câu trả lời của tôi. Bạn có nghĩa là tôi phải thêm tất cả các giải pháp có thể cho câu trả lời của tôi? Bên cạnh các giải pháp bạn đề xuất sẽ tạo ra một data.frame hoàn toàn mới trong khi điều này cập nhật dữ liệu ban đầu. Có thể bằng cách tham chiếu: -O. – Arun

+0

Điểm của nhận xét là hy vọng rằng bất cứ ai đọc câu trả lời này nhận ra rằng, ngoài việc làm việc (như bạn trình bày độc đáo) trong 'data.table', cùng một phương thức chung có thể làm việc trong cơ sở và' dplyr'. Tôi nghĩ rằng một tham gia là cách tự nhiên nhất để giải quyết vấn đề OP, nhưng khi OP gắn thẻ 'dplyr' và yêu cầu một giải pháp' dplyr', tôi nghĩ rằng câu trả lời duy nhất sử dụng phương thức join * không * sử dụng 'dplyr '. Tôi cũng muốn để lại một bình luận hơn là thêm một câu trả lời mới-câu hỏi này đã quá nhiều rồi, và sử dụng cùng một phương pháp với cú pháp của gói khác nhau dường như không đủ khác. – Gregor

1

Tôi hơi muộn nhưng đây là giải pháp của tôi bằng cách sử dụng mapply.

vswitch <- function(x, ...) { 
    mapply(FUN = function(x, ...) { 
      switch(x, ...) 
     }, x, ...) 
} 

mutate(df.faithful, y = vswitch(x, y1, y2, y3, y4)) 
Các vấn đề liên quan