it-swarm-ko.tech

`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 개가 아닌 하나의 새 변수 (varname이라고 함) (petal.2-petal.5) 만 만듭니다.

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

124
Timm S.

변수 이름을 문자 값으로 극적으로 구축하고 있으므로 표준 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의 이전 버전에서도 가능합니다. quotesetName을주의해서 사용해야합니다.

# --- 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)
}
140
MrFlick

dplyr (2017 년 4 월 대기중인 0.6.0)의 새 릴리스에서 (:=)을 인용 부호를 지정하여 할당 (!!)을 수행하고 변수를 열 이름으로 전달할 수도 있습니다. 그것을 평가하지 않기 위해

 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'에 적용된 @MrFlick의 multipetal을 기반으로 출력 확인

identical(iris1, iris2)
#[1] TRUE
46
akrun

많은 시행 착오 끝에 패턴 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')
16
Tom Roth

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

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
12
user2946432

나는 또한 답변을 검색 할 때이 항목에 왔기 때문에 이것을 조금 증가시키는 답변을 추가하고 있습니다. 이것은 거의 필요한 것을 가지고 있었지만 조금 더 필요했습니다. 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
4
mpettis

패키지 friendlyeval 을 사용하면 깔끔하고 깔끔한 eval API와 신규/캐주얼 dplyr 사용자를위한 문서를 제공 할 수 있습니다.

mutate에서 열 이름으로 처리 할 문자열을 작성 중입니다. 따라서 friendlyeval을 사용하면 다음과 같이 작성할 수 있습니다.

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

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

후드에서 rlang 함수를 호출하는 varname 함수는 열 이름으로 유효한 것입니다.

friendlyeval 코드는 RStudio addin을 사용하여 언제든지 동등한 일반 깔끔한 평가 코드로 변환 할 수 있습니다.

2
MilesMcBain

대화 형 사용을 위해 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) 
2
hackR