[r] 문자열 벡터 입력을 사용하여 dplyr에서 여러 열로 그룹화

plyr에 대한 이해를 dplyr으로 옮기려고하지만 여러 열로 그룹화하는 방법을 알 수 없습니다.

# make data with weird column names that can't be hard coded
data = data.frame(
  asihckhdoydkhxiydfgfTgdsx = sample(LETTERS[1:3], 100, replace=TRUE),
  a30mvxigxkghc5cdsvxvyv0ja = sample(LETTERS[1:3], 100, replace=TRUE),
  value = rnorm(100)
)

# get the columns we want to average within
columns = names(data)[-3]

# plyr - works
ddply(data, columns, summarize, value=mean(value))

# dplyr - raises error
data %.%
  group_by(columns) %.%
  summarise(Value = mean(value))
#> Error in eval(expr, envir, enclos) : index out of bounds

plyr 예제를 dplyr-esque 구문으로 변환하기 위해 무엇을 놓치고 있습니까?

편집 2017 : Dplyr이 업데이트되었으므로 더 간단한 솔루션을 사용할 수 있습니다. 현재 선택된 답변을 참조하십시오.



답변

이 질문이 게시 된 이후 dplyr은 범위가 지정된 버전 group_by( documentation here )을 추가했습니다. 이를 통해 다음과 같은 기능을 사용할 수 있습니다 select.

data = data.frame(
    asihckhdoydkhxiydfgfTgdsx = sample(LETTERS[1:3], 100, replace=TRUE),
    a30mvxigxkghc5cdsvxvyv0ja = sample(LETTERS[1:3], 100, replace=TRUE),
    value = rnorm(100)
)

# get the columns we want to average within
columns = names(data)[-3]

library(dplyr)
df1 <- data %>%
  group_by_at(vars(one_of(columns))) %>%
  summarize(Value = mean(value))

#compare plyr for reference
df2 <- plyr::ddply(data, columns, plyr::summarize, value=mean(value))
table(df1 == df2, useNA = 'ifany')
## TRUE 
##  27 

예제 질문의 결과는 예상대로입니다 (위의 plyr와 아래의 결과 비교 참조).

# A tibble: 9 x 3
# Groups:   asihckhdoydkhxiydfgfTgdsx [?]
  asihckhdoydkhxiydfgfTgdsx a30mvxigxkghc5cdsvxvyv0ja       Value
                     <fctr>                    <fctr>       <dbl>
1                         A                         A  0.04095002
2                         A                         B  0.24943935
3                         A                         C -0.25783892
4                         B                         A  0.15161805
5                         B                         B  0.27189974
6                         B                         C  0.20858897
7                         C                         A  0.19502221
8                         C                         B  0.56837548
9                         C                         C -0.22682998

dplyr::summarize한 번에 하나의 그룹화 계층 만 제거하기 때문에 결과로 생성되는 티블에서 그룹화가 계속 진행됩니다 (이후에는 나중에 줄을 서서 사람들을 잡을 수 있음). 예기치 않은 그룹화 동작으로부터 완전히 안전 %>% ungroup하려면 요약 후 항상 파이프 라인에 추가 할 수 있습니다 .


답변

코드를 완전히 작성하기 위해 Hadley의 답변에 대한 새로운 구문이 업데이트되었습니다.

library(dplyr)

df <-  data.frame(
    asihckhdoydk = sample(LETTERS[1:3], 100, replace=TRUE),
    a30mvxigxkgh = sample(LETTERS[1:3], 100, replace=TRUE),
    value = rnorm(100)
)

# Columns you want to group by
grp_cols <- names(df)[-3]

# Convert character vector to list of symbols
dots <- lapply(grp_cols, as.symbol)

# Perform frequency counts
df %>%
    group_by_(.dots=dots) %>%
    summarise(n = n())

산출:

Source: local data frame [9 x 3]
Groups: asihckhdoydk

  asihckhdoydk a30mvxigxkgh  n
1            A            A 10
2            A            B 10
3            A            C 13
4            B            A 14
5            B            B 10
6            B            C 12
7            C            A  9
8            C            B 12
9            C            C 10


답변

dplyr에서 이것에 대한 지원은 현재 매우 약합니다. 결국 구문은 다음과 같습니다.

df %.% group_by(.groups = c("asdfgfTgdsx", "asdfk30v0ja"))

그러나 아마도 한동안은 없을 것입니다 (모든 결과를 생각해야하기 때문에).

그 동안에는 regroup()기호 목록을 사용 하는을 사용할 수 있습니다 .

library(dplyr)

df <-  data.frame(
  asihckhdoydk = sample(LETTERS[1:3], 100, replace=TRUE),
  a30mvxigxkgh = sample(LETTERS[1:3], 100, replace=TRUE),
  value = rnorm(100)
)

df %.%
  regroup(list(quote(asihckhdoydk), quote(a30mvxigxkgh))) %.%
  summarise(n = n())

열 이름의 문자형 벡터가있는 경우 lapply()and 를 사용하여 올바른 구조로 변환 할 수 있습니다 as.symbol().

vars <- setdiff(names(df), "value")
vars2 <- lapply(vars, as.symbol)

df %.% regroup(vars2) %.% summarise(n = n())


답변

밑줄로 끝나는 이름을 가진 함수의 dplyr변형을 통해 열의 문자열 지정이 지원됩니다 dplyr. 예를 들어, group_by함수에 대응하여 group_by_문자열 인수를 취할 수 있는 함수가 있습니다. 이 비 네트 에는 이러한 함수의 구문이 자세히 설명되어 있습니다.

다음 스 니펫은 @sharoz가 원래 제기 한 문제를 완전히 해결합니다 ( .dots인수 를 작성할 필요가 있음 ).

# Given data and columns from the OP

data %>%
    group_by_(.dots = columns) %>%
    summarise(Value = mean(value))

dplyr은 이제 %>%연산자를 사용하므로 %.%더 이상 사용되지 않습니다.


답변

dplyr이 문자열 인수를 완전히 지원할 때까지이 요지가 유용 할 수 있습니다.

https://gist.github.com/skranz/9681509

문자열 인수를 사용하는 s_group_by, s_mutate, s_filter 등과 같은 래퍼 함수를 ​​포함합니다. 일반적인 dplyr 기능과 함께 사용할 수 있습니다. 예를 들어

cols = c("cyl","gear")
mtcars %.%
  s_group_by(cols) %.%
  s_summarise("avdisp=mean(disp), max(disp)") %.%
  arrange(avdisp)


답변

캐릭터 벡터가 아닌 객체 (잘, 그렇지는 않지만 …)를 전달하면 작동합니다.

df %.%
    group_by(asdfgfTgdsx, asdfk30v0ja) %.%
    summarise(Value = mean(value))

> df %.%
+   group_by(asdfgfTgdsx, asdfk30v0ja) %.%
+   summarise(Value = mean(value))
Source: local data frame [9 x 3]
Groups: asdfgfTgdsx

  asdfgfTgdsx asdfk30v0ja        Value
1           A           C  0.046538002
2           C           B -0.286359899
3           B           A -0.305159419
4           C           A -0.004741504
5           B           B  0.520126476
6           C           C  0.086805492
7           B           C -0.052613078
8           A           A  0.368410146
9           A           B  0.088462212

어디 df있었어 data?

?group_by 말한다 :

 ...: variables to group by. All tbls accept variable names, some
      will also accept functons of variables. Duplicated groups
      will be silently dropped.

나는 이름의 문자 버전이 아니라 당신이 그것을 어떻게 참조 하는지를 해석합니다 foo$bar. bar여기에 인용되지 않았습니다. 또는 수식에서 변수를 참조하는 방법 : foo ~ bar.

@Arun은 또한 할 수 있다고 언급합니다.

df %.%
    group_by("asdfgfTgdsx", "asdfk30v0ja") %.%
    summarise(Value = mean(value))

그러나 평가되지 않은 것은 데이터 객체의 변수 이름이 아닌 것을 전달할 수 없습니다 .

나는 이것이 Hadley가 당신이 ...인수 를 통해 전달하는 것들을 찾는 데 사용하는 내부 방법 때문이라고 생각합니다 .


답변

data = data.frame(
  my.a = sample(LETTERS[1:3], 100, replace=TRUE),
  my.b = sample(LETTERS[1:3], 100, replace=TRUE),
  value = rnorm(100)
)

group_by(data,newcol=paste(my.a,my.b,sep="_")) %>% summarise(Value=mean(value))