programing

dplyr을 사용하여 테이블의 모든 행에 함수를 적용하시겠습니까?

sourcetip 2023. 6. 22. 00:03
반응형

dplyr을 사용하여 테이블의 모든 행에 함수를 적용하시겠습니까?

로 할 때plyr나는 종종 그것을 사용하는 것이 유용하다고 생각했습니다.adply모든 행에 적용해야 하는 스칼라 함수의 경우.

예.

data(iris)
library(plyr)
head(
     adply(iris, 1, transform , Max.Len= max(Sepal.Length,Petal.Length))
    )
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species Max.Len
1          5.1         3.5          1.4         0.2  setosa     5.1
2          4.9         3.0          1.4         0.2  setosa     4.9
3          4.7         3.2          1.3         0.2  setosa     4.7
4          4.6         3.1          1.5         0.2  setosa     4.6
5          5.0         3.6          1.4         0.2  setosa     5.0
6          5.4         3.9          1.7         0.4  setosa     5.4

이제 사용합니다.dplyr게다가, 저는 이것을 하는 깔끔한/자연스러운 방법이 있는지 궁금합니다.이것은 제가 원하는 것이 아니기 때문에:

library(dplyr)
head(
     mutate(iris, Max.Len= max(Sepal.Length,Petal.Length))
    )
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species Max.Len
1          5.1         3.5          1.4         0.2  setosa     7.9
2          4.9         3.0          1.4         0.2  setosa     7.9
3          4.7         3.2          1.3         0.2  setosa     7.9
4          4.6         3.1          1.5         0.2  setosa     7.9
5          5.0         3.6          1.4         0.2  setosa     7.9
6          5.4         3.9          1.7         0.4  setosa     7.9

0 (생각에는) dplyr 0.2 기제 (준생각))rowwise()되므로 이 은 다음과 같습니다

iris %>% 
  rowwise() %>% 
  mutate(Max.Len= max(Sepal.Length,Petal.Length))

rowwise인 것

5년 후에도(!) 이 답변은 여전히 많은 트래픽을 수신합니다.이후로, 이주어기때문에졌그것때.rowwise많은 사람들이 직관적이라고 생각하는 것처럼 보이지만, 점점 더 권장되지 않습니다.이 주제를 잘 다루기 위해서는 R에서 제니 브라이언의 Row 지향 워크플로우를 깔끔한 버전의 자료로 살펴보세요.

가장 은 해들리의 중 입니다.pmap:

iris %>% 
  mutate(Max.Len= purrr::pmap_dbl(list(Sepal.Length, Petal.Length), max))

하면 함수에 의 수의할 수 ..f ) 안에pmap.

pmap행 단위 연산을 수행할 때 벡터 목록(데이터 프레임의 열)의 튜플로 실제로 작업한다는 사실을 반영하기 때문에 좋은 개념적 접근 방식입니다.

관용적인 접근법은 적절하게 벡터화된 함수를 만드는 것입니다.

R공다하를 합니다.pmax여기에 적합하지만, 그것은 또한 제공합니다.Vectorize의 으로서.mapply임의 함수의 벡터화된 임의 버전을 만들 수 있습니다.

library(dplyr)
# use base R pmax (vectorized in C)
iris %>% mutate(max.len = pmax(Sepal.Length, Petal.Length))
# use vectorize to create your own function
# for example, a horribly inefficient get first non-Na value function
# a version that is not vectorized
coalesce <- function(a,b) {r <- c(a[1],b[1]); r[!is.na(r)][1]}
# a vectorized version
Coalesce <- Vectorize(coalesce, vectorize.args = c('a','b'))
# some example data
df <- data.frame(a = c(1:5,NA,7:10), b = c(1:3,NA,NA,6,NA,10:8))
df %>% mutate(ab =Coalesce(a,b))

하는 것이 C/C++에서 벡터화를 구현하는 것은 .magicPony당신을 위해 기능을 써줄 패키지.

행별로 그룹화해야 합니다.

iris %>% group_by(1:n()) %>% mutate(Max.Len= max(Sepal.Length,Petal.Length))

이것이 바로 그것입니다.1에서 한adply.

2017-08-03 업데이트

이 글을 쓴 후, 해들리는 몇 가지 물건들을 다시 바꿨습니다.purrrr에 있던 함수들은 purrrrr이라고 불리는 새로운 혼합 패키지에 있으며, 다음과 같이 설명됩니다.

purrlyr에는 purrr과 dplyr의 교차점에 있는 일부 함수가 포함되어 있습니다.패키지를 더 가볍게 만들기 위해 그리고 깔끔한 역의 다른 솔루션으로 대체되었기 때문에 퍼런에서 제거되었습니다.

따라서 아래 코드를 작동시키려면 패키지를 설치 + 로드해야 합니다.

원본 게시물

Hadley는 우리가 무엇을 사용해야 하는지에 대해 자주 생각을 바꾸지만, 나는 우리가 by row 기능을 얻기 위해 furrr에 있는 기능으로 전환해야 한다고 생각합니다.적어도, 그들은 동일한 기능을 제공하고 거의 동일한 인터페이스를 가지고 있습니다.adply플라이어에서

두 가지 관련 기능이 있습니다.by_row그리고.invoke_rows제가 알기로는 당신은by_row행을 루프하여 결과를 data.frame에 추가하려는 경우. invoke_rowsdata.frame의 행을 루프하고 각 콜을 함수에 인수로 전달할 때 사용됩니다.우리는 첫 번째 것만 사용할 것입니다.

library(tidyverse)

iris %>% 
  by_row(..f = function(this_row) {
    browser()
  })

이를 통해 내부를 볼 수 있습니다(우리가 무엇을 하고 있는지 알 수 있습니다). 이는 작업을 수행하는 것과 동일합니다.adply.

Called from: ..f(.d[[i]], ...)
Browse[1]> this_row
# A tibble: 1 × 5
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
         <dbl>       <dbl>        <dbl>       <dbl>  <fctr>
1          5.1         3.5          1.4         0.2  setosa
Browse[1]> Q

기본적으로,by_row출력을 기준으로 목록 열을 추가합니다.

iris %>% 
  by_row(..f = function(this_row) {
      this_row[1:4] %>% unlist %>% mean
  })

제공:

# A tibble: 150 × 6
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species      .out
          <dbl>       <dbl>        <dbl>       <dbl>  <fctr>    <list>
1           5.1         3.5          1.4         0.2  setosa <dbl [1]>
2           4.9         3.0          1.4         0.2  setosa <dbl [1]>
3           4.7         3.2          1.3         0.2  setosa <dbl [1]>
4           4.6         3.1          1.5         0.2  setosa <dbl [1]>
5           5.0         3.6          1.4         0.2  setosa <dbl [1]>
6           5.4         3.9          1.7         0.4  setosa <dbl [1]>
7           4.6         3.4          1.4         0.3  setosa <dbl [1]>
8           5.0         3.4          1.5         0.2  setosa <dbl [1]>
9           4.4         2.9          1.4         0.2  setosa <dbl [1]>
10          4.9         3.1          1.5         0.1  setosa <dbl [1]>
# ... with 140 more rows

대신에 우리가 a를 돌려준다면,data.frame우리는 리스트를 얻습니다.data.frames:

iris %>% 
  by_row( ..f = function(this_row) {
    data.frame(
      new_col_mean = this_row[1:4] %>% unlist %>% mean,
      new_col_median = this_row[1:4] %>% unlist %>% median
    )
  })

제공:

# A tibble: 150 × 6
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species                 .out
          <dbl>       <dbl>        <dbl>       <dbl>  <fctr>               <list>
1           5.1         3.5          1.4         0.2  setosa <data.frame [1 × 2]>
2           4.9         3.0          1.4         0.2  setosa <data.frame [1 × 2]>
3           4.7         3.2          1.3         0.2  setosa <data.frame [1 × 2]>
4           4.6         3.1          1.5         0.2  setosa <data.frame [1 × 2]>
5           5.0         3.6          1.4         0.2  setosa <data.frame [1 × 2]>
6           5.4         3.9          1.7         0.4  setosa <data.frame [1 × 2]>
7           4.6         3.4          1.4         0.3  setosa <data.frame [1 × 2]>
8           5.0         3.4          1.5         0.2  setosa <data.frame [1 × 2]>
9           4.4         2.9          1.4         0.2  setosa <data.frame [1 × 2]>
10          4.9         3.1          1.5         0.1  setosa <data.frame [1 × 2]>
# ... with 140 more rows

은 함의출추방는다법통제음다어에 의해 됩니다..collateparam., param의 세옵션이 . 세 가지 옵션이 있습니다. 목록, 행, 콜입니다.출력 길이가 1이면 행을 사용하든 콜을 사용하든 상관 없습니다.

iris %>% 
  by_row(.collate = "cols", ..f = function(this_row) {
    this_row[1:4] %>% unlist %>% mean
  })

iris %>% 
  by_row(.collate = "rows", ..f = function(this_row) {
    this_row[1:4] %>% unlist %>% mean
  })

두 제품 모두:

# A tibble: 150 × 6
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  .out
          <dbl>       <dbl>        <dbl>       <dbl>  <fctr> <dbl>
1           5.1         3.5          1.4         0.2  setosa 2.550
2           4.9         3.0          1.4         0.2  setosa 2.375
3           4.7         3.2          1.3         0.2  setosa 2.350
4           4.6         3.1          1.5         0.2  setosa 2.350
5           5.0         3.6          1.4         0.2  setosa 2.550
6           5.4         3.9          1.7         0.4  setosa 2.850
7           4.6         3.4          1.4         0.3  setosa 2.425
8           5.0         3.4          1.5         0.2  setosa 2.525
9           4.4         2.9          1.4         0.2  setosa 2.225
10          4.9         3.1          1.5         0.1  setosa 2.400
# ... with 140 more rows

data.frame을 1개의 행으로 출력하면 다음과 같이 사용하는 것이 약간만 중요합니다.

iris %>% 
  by_row(.collate = "cols", ..f = function(this_row) {
    data.frame(
      new_col_mean = this_row[1:4] %>% unlist %>% mean,
      new_col_median = this_row[1:4] %>% unlist %>% median
      )
  })

iris %>% 
  by_row(.collate = "rows", ..f = function(this_row) {
    data.frame(
      new_col_mean = this_row[1:4] %>% unlist %>% mean,
      new_col_median = this_row[1:4] %>% unlist %>% median
    )
  })

둘 다 제공:

# A tibble: 150 × 8
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species  .row new_col_mean new_col_median
          <dbl>       <dbl>        <dbl>       <dbl>  <fctr> <int>        <dbl>          <dbl>
1           5.1         3.5          1.4         0.2  setosa     1        2.550           2.45
2           4.9         3.0          1.4         0.2  setosa     2        2.375           2.20
3           4.7         3.2          1.3         0.2  setosa     3        2.350           2.25
4           4.6         3.1          1.5         0.2  setosa     4        2.350           2.30
5           5.0         3.6          1.4         0.2  setosa     5        2.550           2.50
6           5.4         3.9          1.7         0.4  setosa     6        2.850           2.80
7           4.6         3.4          1.4         0.3  setosa     7        2.425           2.40
8           5.0         3.4          1.5         0.2  setosa     8        2.525           2.45
9           4.4         2.9          1.4         0.2  setosa     9        2.225           2.15
10          4.9         3.1          1.5         0.1  setosa    10        2.400           2.30
# ... with 140 more rows

두 는 두번열 다과같열은있것이제는을고라는 있는 는,.row첫 번째는 그렇지 않습니다.

" 보막으로마", " 우의출길이력이길 1다나거리지"로 됩니다.vector또는 로서data.frame행을할지, 합니다..collate:

mtcars[1:2] %>% by_row(function(x) 1:5)
mtcars[1:2] %>% by_row(function(x) 1:5, .collate = "rows")
mtcars[1:2] %>% by_row(function(x) 1:5, .collate = "cols")

각각 다음을 생성합니다.

# A tibble: 32 × 3
     mpg   cyl      .out
   <dbl> <dbl>    <list>
1   21.0     6 <int [5]>
2   21.0     6 <int [5]>
3   22.8     4 <int [5]>
4   21.4     6 <int [5]>
5   18.7     8 <int [5]>
6   18.1     6 <int [5]>
7   14.3     8 <int [5]>
8   24.4     4 <int [5]>
9   22.8     4 <int [5]>
10  19.2     6 <int [5]>
# ... with 22 more rows

# A tibble: 160 × 4
     mpg   cyl  .row  .out
   <dbl> <dbl> <int> <int>
1     21     6     1     1
2     21     6     1     2
3     21     6     1     3
4     21     6     1     4
5     21     6     1     5
6     21     6     2     1
7     21     6     2     2
8     21     6     2     3
9     21     6     2     4
10    21     6     2     5
# ... with 150 more rows

# A tibble: 32 × 7
     mpg   cyl .out1 .out2 .out3 .out4 .out5
   <dbl> <dbl> <int> <int> <int> <int> <int>
1   21.0     6     1     2     3     4     5
2   21.0     6     1     2     3     4     5
3   22.8     4     1     2     3     4     5
4   21.4     6     1     2     3     4     5
5   18.7     8     1     2     3     4     5
6   18.1     6     1     2     3     4     5
7   14.3     8     1     2     3     4     5
8   24.4     4     1     2     3     4     5
9   22.8     4     1     2     3     4     5
10  19.2     6     1     2     3     4     5
# ... with 22 more rows

자, 결론은.만약 당신이 원한다면,adply(.margins = 1, ...) 기능성을 할 수 .by_row.

BrodieG의 답변을 연장합니다.

가 두 개을 반환하는 에는 "" " " " " " " " 대신에 " " " 를 합니다.mutate(),do()사용해야 합니다.그런 다음 다시 결합하려면 다음을 사용합니다.rbind_all()dplyr꾸러미

dplyrdplyr_0.1.2를 사용합니다.1:n()에 시대에group_by()조항은 저에게 통하지 않습니다.해들리가 곧 실행되기를 바랍니다.

iris %>%
    group_by(1:nrow(iris)) %>%
    do(do_fn) %>%
    rbind_all()

성능 테스트 중,

library(plyr)    # plyr_1.8.4.9000
library(dplyr)   # dplyr_0.8.0.9000
library(purrr)   # purrr_0.2.99.9000
library(microbenchmark)

d1_count <- 1000
d2_count <- 10

d1 <- data.frame(a=runif(d1_count))

do_fn <- function(row){data.frame(a=row$a, b=runif(d2_count))}
do_fn2 <- function(a){data.frame(a=a, b=runif(d2_count))}

op <- microbenchmark(
        plyr_version = plyr::adply(d1, 1, do_fn),
        dplyr_version = d1 %>%
            dplyr::group_by(1:nrow(d1)) %>%
            dplyr::do(do_fn(.)) %>%
            dplyr::bind_rows(),
        purrr_version = d1 %>% purrr::pmap_dfr(do_fn2),
        times=50)

결과는 다음과 같습니다.

Unit: milliseconds
          expr       min        lq      mean    median        uq       max neval
  plyr_version 1227.2589 1275.1363 1317.3431 1293.5759 1314.4266 1616.5449    50
 dplyr_version  977.3025 1012.6340 1035.9436 1025.6267 1040.5882 1449.0978    50
 purrr_version  609.5790  629.7565  643.8498  644.2505  656.1959  686.8128    50

이것은 새로운 것을 보여줍니다.purrr이 .

이런 거?

iris$Max.Len <- pmax(iris$Sepal.Length, iris$Petal.Length)

@alexhan이 제공하는 훌륭한 답변 외에도, 당신은 사용할 필요가 있다는 것을 명심하세요.ungroup()부작용을 피하기 위해.는 는이유 때문입니다.rowwise()그룹화 작업입니다.

iris %>%
    rowwise() %>%
    mutate(Max.Len = max(Sepal.Length, Petal.Length))

다음을 제공합니다.

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species Max.Len
          <dbl>       <dbl>        <dbl>       <dbl> <fct>     <dbl>
 1          5.1         3.5          1.4         0.2 setosa      5.1
 2          4.9         3            1.4         0.2 setosa      4.9
 3          4.7         3.2          1.3         0.2 setosa      4.7
 4          4.6         3.1          1.5         0.2 setosa      4.6
 5          5           3.6          1.4         0.2 setosa      5  
 6          5.4         3.9          1.7         0.4 setosa      5.4
 7          4.6         3.4          1.4         0.3 setosa      4.6
 8          5           3.4          1.5         0.2 setosa      5  
 9          4.4         2.9          1.4         0.2 setosa      4.4
10          4.9         3.1          1.5         0.1 setosa      4.9

이제 다음 단계를 계속 진행해야 한다고 가정해 보겠습니다.dplyr추할파프를 leadMax.Len:

iris %>%
    rowwise() %>%
    mutate(Max.Len = max(Sepal.Length, Petal.Length)) %>%
    mutate(Lead.Max.Len = lead(Max.Len))

이를 통해 다음과 같은 결과를 얻을 수:

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species Max.Len Lead.Max.Len
          <dbl>       <dbl>        <dbl>       <dbl> <fct>     <dbl>        <dbl>
 1          5.1         3.5          1.4         0.2 setosa      5.1           NA
 2          4.9         3            1.4         0.2 setosa      4.9           NA
 3          4.7         3.2          1.3         0.2 setosa      4.7           NA
 4          4.6         3.1          1.5         0.2 setosa      4.6           NA
 5          5           3.6          1.4         0.2 setosa      5             NA
 6          5.4         3.9          1.7         0.4 setosa      5.4           NA
 7          4.6         3.4          1.4         0.3 setosa      4.6           NA
 8          5           3.4          1.5         0.2 setosa      5             NA
 9          4.4         2.9          1.4         0.2 setosa      4.4           NA
10          4.9         3.1          1.5         0.1 setosa      4.9           NA

NA는 부작용으로 생성됩니다.이 문제는 다음을 통해 해결할 수 있습니다.ungroup():

iris %>%
    rowwise() %>%
    mutate(Max.Len = max(Sepal.Length, Petal.Length)) %>%
    ungroup() %>%
    mutate(Lead.Max.Len = lead(Max.Len))

이렇게 하면 원하는 출력이 생성됩니다.

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species Max.Len lead.max.len
          <dbl>       <dbl>        <dbl>       <dbl> <fct>     <dbl>        <dbl>
 1          5.1         3.5          1.4         0.2 setosa      5.1          4.9
 2          4.9         3            1.4         0.2 setosa      4.9          4.7
 3          4.7         3.2          1.3         0.2 setosa      4.7          4.6
 4          4.6         3.1          1.5         0.2 setosa      4.6          5  
 5          5           3.6          1.4         0.2 setosa      5            5.4
 6          5.4         3.9          1.7         0.4 setosa      5.4          4.6
 7          4.6         3.4          1.4         0.3 setosa      4.6          5  
 8          5           3.4          1.5         0.2 setosa      5            4.4
 9          4.4         2.9          1.4         0.2 setosa      4.4          4.9
10          4.9         3.1          1.5         0.1 setosa      4.9          5.4

완전성을 위해 이 사용자의 코드를 질문의 잊혀진 답변(아마도 가장 좋은 답변)에서 변경하려고 합니다.여러 열에 걸친 합계입니다.문제에 적용할 수 있습니다.

iris %>%
  mutate(max = select(.,c('Sepal.Length','Petal.Length')) %>% 
  apply(1, max, na.rm=TRUE))

결과가 예상됩니다.수용된 답변은 행 단위로 사용하는 것이 점점 더 권장되지 않으며 기본 R을 적용합니다.당신은 purr과 같은 추가 패키지를 수입할 필요가 없습니다.

최대값, 최소값, 합, 중위수, 평균에 적용() 함수를 사용할 수 있습니다.그래서 매우 편리하고 간단합니다.

언급URL : https://stackoverflow.com/questions/21818181/applying-a-function-to-every-row-of-a-table-using-dplyr

반응형