[r] `dplyr`에서 동적 변수 이름 사용

dplyr::mutate()데이터 프레임에서 여러 개의 새 열을 만드는 데 사용하고 싶습니다 . 열 이름과 해당 내용은 동적으로 생성되어야합니다.

홍채의 데이터 예 :

library(dplyr)
iris <- tbl_df(iris)

Petal.Width변수 에서 새 열을 변경하는 함수를 만들었습니다 .

multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    df <- mutate(df, varname = Petal.Width * n)  ## problem arises here
    df
}

이제 열을 만들기 위해 루프를 만듭니다.

for(i in 2:5) {
    iris <- multipetal(df=iris, n=i)
}

그러나 mutate는 varname이 리터럴 변수 이름이라고 생각하기 때문에 루프는 4 개 대신 petal.2-petal.5라는 하나의 새 변수 (varname이라고 함) 만 만듭니다.

mutate()동적 이름을 변수 이름으로 사용하려면 어떻게 해야합니까?



답변

변수 이름을 문자 값으로 동적으로 작성하므로 표준 data.frame 인덱싱을 사용하여 열 이름에 문자 값을 지정할 수 있습니다. 예를 들면 다음과 같습니다.

multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    df[[varname]] <- with(df, Petal.Width * n)
    df
}

mutate함수를 사용하면 명명 된 매개 변수를 통해 새 열의 이름을 쉽게 지정할 수 있습니다. 그러나 명령을 입력 할 때 이름을 알고 있다고 가정합니다. 열 이름을 동적으로 지정하려면 명명 된 인수도 작성해야합니다.


dplyr 버전> = 0.7

최신 버전 dplyr(0.7)은 :=매개 변수 이름을 동적으로 할당 하는 데 사용하여이 작업을 수행 합니다. 함수를 다음과 같이 작성할 수 있습니다.

# --- dplyr version 0.7+---
multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    mutate(df, !!varname := Petal.Width * n)
}

자세한 내용은 사용 가능한 설명서를 참조하십시오 vignette("programming", "dplyr").


dplyr (> = 0.3 및 <0.7)

약간 이전 버전 dplyr(> = 0.3 <0.7)에서는 많은 기능에 대한 “표준 평가”대안을 사용하도록 권장했습니다. 자세한 내용은 비표준 평가 비 네트를 참조하십시오 ( vignette("nse")).

따라서 여기에 대한 대답은 사용 mutate_()하기보다는 사용 하는 것입니다 mutate().

# --- dplyr version 0.3-0.5---
multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    varval <- lazyeval::interp(~Petal.Width * n, n=n)
    mutate_(df, .dots= setNames(list(varval), varname))
}

dplyr <0.3

이것은 dplyr질문이 처음 제기되었을 때 존재했던 이전 버전에서도 가능합니다 . 그것은의 신중한 사용을 필요로 quote하고을 setName:

# --- dplyr versions < 0.3 ---
multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    pp <- c(quote(df), setNames(list(quote(Petal.Width * n)), varname))
    do.call("mutate", pp)
}


답변

dplyr( 0.6.02017 년 4 월 대기 중)의 새로운 릴리스에서는 할당하지 :=않고 ( !!)를 지정하여 변수를 열 이름으로 전달하고 ( ) 변수를 열 이름으로 전달할 수도 있습니다.

 library(dplyr)
 multipetalN <- function(df, n){
      varname <- paste0("petal.", n)
      df %>%
         mutate(!!varname := Petal.Width * n)
 }

 data(iris)
 iris1 <- tbl_df(iris)
 iris2 <- tbl_df(iris)
 for(i in 2:5) {
     iris2 <- multipetalN(df=iris2, n=i)
 }   

@ iris1 ‘에 multipetal적용된 @MrFlick을 기반으로 출력 확인

identical(iris1, iris2)
#[1] TRUE


답변

많은 시행 착오 끝에 패턴 UQ(rlang::sym("some string here")))이 문자열 및 dplyr 동사 작업에 실제로 유용하다는 것을 알았습니다 . 많은 놀라운 상황에서 작동하는 것 같습니다.

의 예는 다음과 같습니다 mutate. 두 개의 열을 더하는 함수를 만들고 싶습니다. 두 개의 열 이름을 모두 문자열로 전달합니다. 할당 연산자와 함께이 패턴을 사용하여이를 수행 할 수 있습니다 :=.

## Take column `name1`, add it to column `name2`, and call the result `new_name`
mutate_values <- function(new_name, name1, name2){
  mtcars %>%
    mutate(UQ(rlang::sym(new_name)) :=  UQ(rlang::sym(name1)) +  UQ(rlang::sym(name2)))
}
mutate_values('test', 'mpg', 'cyl')

이 패턴은 다른 dplyr기능과도 작동 합니다. 여기 있습니다 filter:

## filter a column by a value 
filter_values <- function(name, value){
  mtcars %>%
    filter(UQ(rlang::sym(name)) != value)
}
filter_values('gear', 4)

또는 arrange:

## transform a variable and then sort by it 
arrange_values <- function(name, transform){
  mtcars %>%
    arrange(UQ(rlang::sym(name)) %>%  UQ(rlang::sym(transform)))
}
arrange_values('mpg', 'sin')

의 경우 select패턴을 사용할 필요가 없습니다. 대신 다음을 사용할 수 있습니다 !!.

## select a column 
select_name <- function(name){
  mtcars %>%
    select(!!name)
}
select_name('mpg')


답변

여기 또 다른 버전이 있으며 약간 더 간단합니다.

multipetal <- function(df, n) {
    varname <- paste("petal", n, sep=".")
    df<-mutate_(df, .dots=setNames(paste0("Petal.Width*",n), varname))
    df
}

for(i in 2:5) {
    iris <- multipetal(df=iris, n=i)
}

> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species petal.2 petal.3 petal.4 petal.5
1          5.1         3.5          1.4         0.2  setosa     0.4     0.6     0.8       1
2          4.9         3.0          1.4         0.2  setosa     0.4     0.6     0.8       1
3          4.7         3.2          1.3         0.2  setosa     0.4     0.6     0.8       1
4          4.6         3.1          1.5         0.2  setosa     0.4     0.6     0.8       1
5          5.0         3.6          1.4         0.2  setosa     0.4     0.6     0.8       1
6          5.4         3.9          1.7         0.4  setosa     0.8     1.2     1.6       2


답변

함께 rlang 0.4.0우리는 곱슬 곱슬 연산자 (이 {{}}) 매우 쉽게이를 수있다.

library(dplyr)
library(rlang)

iris1 <- tbl_df(iris)

multipetal <- function(df, n) {
   varname <- paste("petal", n , sep=".")
   mutate(df, {{varname}} := Petal.Width * n)
}

multipetal(iris1, 4)

# A tibble: 150 x 6
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species petal.4
#          <dbl>       <dbl>        <dbl>       <dbl> <fct>     <dbl>
# 1          5.1         3.5          1.4         0.2 setosa      0.8
# 2          4.9         3            1.4         0.2 setosa      0.8
# 3          4.7         3.2          1.3         0.2 setosa      0.8
# 4          4.6         3.1          1.5         0.2 setosa      0.8
# 5          5           3.6          1.4         0.2 setosa      0.8
# 6          5.4         3.9          1.7         0.4 setosa      1.6
# 7          4.6         3.4          1.4         0.3 setosa      1.2
# 8          5           3.4          1.5         0.2 setosa      0.8
# 9          4.4         2.9          1.4         0.2 setosa      0.8
#10          4.9         3.1          1.5         0.1 setosa      0.4
# … with 140 more rows

또한 인용 / 따옴표없는 변수 이름을 전달하여 열 이름으로 지정할 수 있습니다.

multipetal <- function(df, name, n) {
   mutate(df, {{name}} := Petal.Width * n)
}

multipetal(iris1, temp, 3)

# A tibble: 150 x 6
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  temp
#          <dbl>       <dbl>        <dbl>       <dbl> <fct>   <dbl>
# 1          5.1         3.5          1.4         0.2 setosa  0.6  
# 2          4.9         3            1.4         0.2 setosa  0.6  
# 3          4.7         3.2          1.3         0.2 setosa  0.6  
# 4          4.6         3.1          1.5         0.2 setosa  0.6  
# 5          5           3.6          1.4         0.2 setosa  0.6  
# 6          5.4         3.9          1.7         0.4 setosa  1.2  
# 7          4.6         3.4          1.4         0.3 setosa  0.900
# 8          5           3.4          1.5         0.2 setosa  0.6  
# 9          4.4         2.9          1.4         0.2 setosa  0.6  
#10          4.9         3.1          1.5         0.1 setosa  0.3  
# … with 140 more rows

그것은 같은 작동합니다

multipetal(iris1, "temp", 3)


답변

나는 또한 답변을 검색 할 때이 항목에 왔기 때문에 이것을 조금 증가시키는 답변을 추가하고 있습니다. 이것은 거의 필요한 것이었지만 조금 더 필요했습니다. R 게으른 짤막한.

문자열에서 Date 객체로 변환하려는 데이터 프레임과 열 이름 (문자열) 벡터를 취할 수있는 함수를 만들고 싶었습니다. 만드는 법을 알 수 없었습니다as.Date()문자열 인 인수를 가져 와서 열로 변환 아래 표시된 것처럼 수행했습니다.

아래는 SE mutate ( mutate_())와 .dots인수를 통해이 작업을 수행 한 방법 입니다. 더 나은 비판은 환영합니다.

library(dplyr)

dat <- data.frame(a="leave alone",
                  dt="2015-08-03 00:00:00",
                  dt2="2015-01-20 00:00:00")

# This function takes a dataframe and list of column names
# that have strings that need to be
# converted to dates in the data frame
convertSelectDates <- function(df, dtnames=character(0)) {
    for (col in dtnames) {
        varval <- sprintf("as.Date(%s)", col)
        df <- df %>% mutate_(.dots= setNames(list(varval), col))
    }
    return(df)
}

dat <- convertSelectDates(dat, c("dt", "dt2"))
dat %>% str


답변

대화 형 사용을 위해 dplyr을 사용하는 것이 좋지만 lazyeval :: interp (), setNames 등의 해결 방법을 사용하기 위해 농구대를 거쳐야하기 때문에 dplyr을 사용 하여이 작업을 수행하는 것은 매우 까다로운 방법입니다.

여기에 기본 R을 사용하는 간단한 버전이 있습니다.이 기능은 루프를 함수 안에 넣고 @MrFlicks의 솔루션을 확장하는 것이 더 직관적입니다.

multipetal <- function(df, n) {
   for (i in 1:n){
      varname <- paste("petal", i , sep=".")
      df[[varname]] <- with(df, Petal.Width * i)
   }
   df
}
multipetal(iris, 3)