2015-02-26 3 views
12

у меня есть data.frame, такие как это (реальный набор данных имеет гораздо больше строк и столбцов)Выполнение dplyr мутировать на подмножества столбцов

set.seed(15) 
dd <- data.frame(id=letters[1:4], matrix(runif(5*4), nrow=4)) 

# id  X1  X2  X3  X4  X5 
# 1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 
# 2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 
# 3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 
# 4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 

Я хотел бы иметь возможность написать dplyr заявление, в котором Я могу выбрать подмножество столбцов и изменить их. (Я пытаюсь сделать что-то похожее на использование .SDcols в data.table).

Для упрощенного примера, вот функция, которую я хотел бы написать для добавления столбцов для сумм и средств четных столбцов «Х» при сохранении всех остальных столбцов. Желаемый выход с использованием основания R равен

(cols<-paste0("X", c(2,4))) 
# [1] "X2" "X4" 
cbind(dd,evensum=rowSums(dd[,cols]),evenmean=rowMeans(dd[,cols])) 

# id  X1  X2  X3  X4  X5 evensum evenmean 
# 1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.4380811 
# 2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.8477439 
# 3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.8387535 
# 4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.5478768 

, но я хотел использовать цепочку типа dplyr, чтобы сделать то же самое. В общем случае я хотел бы использовать любую вспомогательную функцию select(), такую ​​как starts_with, ends_with, matches и т. Д. И любую функцию. Вот что я пытался

library(dplyr) 
partial_mutate1 <- function(x, colspec, ...) { 
    select_(x, .dots=list(lazyeval::lazy(colspec))) %>% 
    transmute_(.dots=lazyeval::lazy_dots(...)) %>% 
    cbind(x,.) 
} 

dd %>% partial_mutate1(num_range("X", c(2,4)), 
    evensum=rowSums(.), evenmean=rowMeans(.)) 

Однако это выдает ошибку, которая говорит

Error in rowSums(.) : 'x' must be numeric 

который, кажется, потому что ., кажется, имея в виду весь date.frame, а не выбранного подмножества. (та же ошибка, что и rowSums(dd)). Однако обратите внимание, что это дает желаемый результат

partial_mutate2 <- function(x, colspec) { 
    select_(x, .dots=list(lazyeval::lazy(colspec))) %>% 
    transmute(evensum=rowSums(.), evenmean=rowMeans(.)) %>% 
    cbind(x,.) 
} 
dd %>% partial_mutate2(seq(2,ncol(dd),2)) 

Я предполагаю, что это какая-то проблема с окружающей средой? Любые предложения о том, как передать аргументы partial_mutate1, чтобы . правильно принял значения из набора данных «select() - ed»?

+0

Безобразная способом было бы: 'дд%>% выбора (Х2, Х4)%>% мутируют (evensum = rowSums(), evenmean = rowMeans()..)%>% выберите (- X2, -X4)%>% cbind (., Dd) ' –

+0

Я подозреваю, что проблема в том, что попытка SE возится с '%>%'. Другими словами, с 'rowMeans (.)' Burried внутри '.dots','%>% 'не может знать, что он должен также подставлять данные. Это просто догадка. – BrodieG

+0

Я думаю, что ты прав @BrodieG.После немного большего количества копаний это больше проблема magrittr, чем проблема dplyr. Например: 'mutate (dd [, - 1], sums = rowSums (.))' Не работает ("object '.' Not found"). Знак '.' не является особым для' dplyr'. Попытка использовать его для применения функции по столбцам кажется неправильной идеей. Думаю, я должен сначала переформатировать данные в «опрятный» формат. – MrFlick

ответ

7

Могу ли я что-то отсутствует или будет эта работа, как и ожидалось:

cols <- paste0("X", c(2,4)) 
dd %>% mutate(evensum = rowSums(.[cols]), evenmean = rowMeans(.[cols])) 
# id  X1  X2  X3  X4  X5 evensum evenmean 
#1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.4380811 
#2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.8477439 
#3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.8387535 
#4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.5478768 

Или вы специально искали для пользовательской функции, чтобы сделать это?


Не совсем то, что вы ищете, но если вы хотите сделать это внутри трубы можно использовать select явно внутри mutate как это:

dd %>% mutate(xy = select(., num_range("X", c(2,4))) %>% rowSums) 
# id  X1  X2  X3  X4  X5  xy 
#1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 
#2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 
#3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 
#4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 

Однако, это немного сложнее, если вы хотите применить несколько функций. Вы можете использовать вспомогательную функцию по линиям (..не тщательно протестирован ..):

f <- function(x, ...) { 
    n <- nrow(x) 
    x <- lapply(list(...), function(y) if (length(y) == 1L) rep(y, n) else y) 
    matrix(unlist(x), nrow = n, byrow = FALSE) 
} 

А затем применить его так:

dd %>% mutate(xy = select(., num_range("X", c(2,4))) %>% f(., rowSums(.), max(.))) 
# id  X1  X2  X3  X4  X5  xy.1  xy.2 
#1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.9888592 
#2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.9888592 
#3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.9888592 
#4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.9888592 
+0

Недостающая часть заключается в том, что я хотел бы использовать функции выбора столбца, которые '' select' предоставляет такие, как start_with, ends_with и т. Д. Это не будет работать «красиво» вне 'select()'. – MrFlick

+0

@MrFlick, ah okay .. –

+1

Конечно, я мог бы использовать 'cols <- dplyr ::: num_range (имена (dd)," X ", c (2,4))'. Дело в том, что это не будет частью цепочки, и оно также сломается, если любые порядки столбцов будут изменены в цепочке после вычисления индексов столбцов. Было бы лучше сделать это «по запросу», если возможно – MrFlick

2

ряд-из-столбцов агностик подхода с использованием dplyr:

dd %>% 
    select(-id) %>% 
    mutate(evensum = rowSums(.[,1:length(.[1,])%%2==0]), 
     evenmean = rowMeans(.[,1:length(.[1,])%%2==0])) %>% 
    cbind(id=dd[,1],.) 

    id  X1  X2  X3  X4  X5 evensum evenmean 
1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.4380812 
2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.8477439 
3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.8387535 
4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.5478767 
Смежные вопросы