programing

'dplyr'의 새 열/변수에 동적 이름 사용

powerit 2023. 7. 2. 21:05
반응형

'dplyr'의 새 열/변수에 동적 이름 사용

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

홍채의 데이터 예제:

library(dplyr)
iris <- as_tibble(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 버전 >= 1.0

에서는 "dplyr 버서는사구있수다니습"의 구문을 할 수 .glue 시 매개변수 시 (package):=에 그서여기에래여기.{}이름에서 내부 식을 평가하여 값을 가져옵니다.

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

열 이름을 사용할 수 있습니다.{{}}뿐 아니라 에서도 사용할 수 .

meanofcol <- function(df, col) {
  mutate(df, "Mean of {{col}}" := mean({{col}}))
}
meanofcol(iris, Petal.Width)


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), 많은 기능에 대한 "표준 평가" 대안의 사용을 장려했습니다. evaluation (비표준 평가 vignett)을 참조하십시오.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.0 in 2017년 4월 4일), 과제(2017년 4월 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)
 }   

@@MrFlik에 한 출력 multipetaliris1''에

identical(iris1, iris2)
#[1] TRUE

많은 시행착오 끝에 패턴을 찾았습니다.!!rlang::sym("my variable"))의 R: (R 전버서는에이전::UQ(rlang::sym("my variable"))) 및 합니다.) 문자열 및 dplyr 동사 작업에 매우 유용합니다.그것은 많은 놀라운 상황에서 작동하는 것처럼 보입니다.

▁example다니예입▁here▁ans'에 대한 예를 들어보겠습니다.mutate두 열을 함께 추가하는 함수를 만들고, 두 열 이름을 모두 문자열로 전달하려고 합니다.이 패턴을 연산자인 이패을연할함께수있다습니사용할과 함께 할 수 .:=이를 위해.

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

패턴은 다른 패턴과 함께 작동합니다.dplyr기능도 제공합니다. »filter:

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

또는arrange:

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

위해서select패턴을 사용할 필요가 없습니다.에 대사용수있다니습할신을 할 수 .!!:

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

우리는 곱슬곱슬한 연산자를 가지고 있습니다.{{}}를 매우 수 있습니다 이것은 이것을 매우 쉽게 만듭니다.열, 동열이할당왼나쪽면타나에의이름적을 사용합니다.:=.

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)

여기 다른 버전이 있는데, 거의 틀림없이 조금 더 단순합니다.

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

최신/캐주얼용으로 간소화된 깔끔한 평가 API와 문서를 제공하는 패키지를 즐길 수 있습니다.dplyruser.sys입니다.

.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을 사용하여 언제든지 동등한 평이한 평가 코드로 변환할 수 있습니다.

제가 답변을 검색할 때 이 항목에 왔는데, 이것이 제가 필요로 하는 것과 거의 같았지만, @MrFlik의 답변과 Lazyeval vignetes를 통해 얻은 것이 조금 더 필요했기 때문에 저는 이것을 조금 더 보강하는 답변을 추가합니다.

문자열에서 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을 사용하는 것을 즐기지만, lazyval::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) 

다른 다른대: 사용을 합니다.{}동적 이름을 쉽게 만들 수 있는 내부 따옴표입니다.이것은 다른 솔루션과 비슷하지만 완전히 같지는 않으며, 저는 더 쉽다고 생각합니다.

library(dplyr)
library(tibble)

iris <- as_tibble(iris)

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

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

은 는이것이에서 온 것 같습니다.dplyr 1.0.0하지만 확실하지 않습니다. (저도 가지고 있습니다.)rlang 4.7.0중요한 경우)

동일한 작업이 여러 번 필요한 경우 일반적으로 데이터 형식이 최적이 아님을 나타냅니다. 원을는경우로 더 긴 .n교차 결합을 통해 달성할 수 있는 data.frame의 열:

library(tidyverse)
iris %>% mutate(identifier = 1:n()) %>% #necessary to disambiguate row 102 from row 143 (complete duplicates)
   full_join(tibble(n = 1:5), by=character()) %>% #cross join for long format
   mutate(petal = Petal.Width * n) %>% #calculation in long format
   pivot_wider(names_from=n, values_from=petal, names_prefix="petal.width.") #back to wider format (if desired)

결과:

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

언급URL : https://stackoverflow.com/questions/26003574/use-dynamic-name-for-new-column-variable-in-dplyr

반응형