r - 합치기 - 각 행의 여러 인수를 사용하여 데이터 프레임의 각 행에 apply-like 함수 호출




데이터 프레임 을 리스트 로 (7)

여러 열이있는 데이터 프레임이 있습니다. 데이터 프레임의 각 행에 대해 행에 함수를 호출하고 함수의 입력에서 해당 행의 여러 열을 사용하고 있습니다. 예를 들어,이 데이터와 두 개의 인수를 허용하는이 testFunc가 있다고 가정 해 봅시다.

> df <- data.frame(x=c(1,2), y=c(3,4), z=c(5,6))
> df
  x y z
1 1 3 5
2 2 4 6
> testFunc <- function(a, b) a + b

이 testFunc을 x와 z 열에 적용하려고한다고 가정 해 봅시다. 그래서 행 1에 대해 1 + 5를 원하고 행 2에 2 + 6을 원한다. for 루프를 작성하지 않고 어쩌면 적용 함수 패밀리를 사용하여이 작업을 수행 할 수있는 방법이 있습니까?

나는 이것을 시도했다 :

> df[,c('x','z')]
  x z
1 1 5
2 2 6
> lapply(df[,c('x','z')], testFunc)
Error in a + b : 'b' is missing

하지만 오류가있어, 어떤 생각?

편집 : 전화를 원하는 실제 함수는 간단한 합계가 아니지만 그것은 power.t.test입니다. 예를 들어 + b를 사용했습니다. 최종 목표는 다음과 같이 (의사 코드로 작성) 할 수 있습니다.

df = data.frame(
    delta=c(delta_values), 
    power=c(power_values), 
    sig.level=c(sig.level_values)
)

lapply(df, power.t.test(delta_from_each_row_of_df, 
                        power_from_each_row_of_df, 
                        sig.level_from_each_row_of_df
))

여기서 결과는 df의 각 행에 대한 power.t.test의 출력 벡터입니다.


dplyr 패키지의 새로운 대답

적용 할 함수가 벡터화 된 경우 dplyr 패키지의 mutate 함수를 사용할 수 있습니다.

> library(dplyr)
> myf <- function(tens, ones) { 10 * tens + ones }
> x <- data.frame(hundreds = 7:9, tens = 1:3, ones = 4:6)
> mutate(x, value = myf(tens, ones))
  hundreds tens ones value
1        7    1    4    14
2        8    2    5    25
3        9    3    6    36

plyr 패키지를 plyr 이전 답변

나의 겸허 한 의견에서, 작업에 가장 적합한 도구는 plyr 패키지에 있습니다.

예:

> library(plyr)
> x <- data.frame(tens = 1:3, ones = 4:6)
> mdply(x, function(tens, ones) { 10 * tens + ones })
  tens ones V1
1    1    4 14
2    2    5 25
3    3    6 36

불행히도, Bertjan Broeksema가 지적했듯이, mdply 호출에서 데이터 프레임의 모든 컬럼을 사용하지 않으면이 접근법이 실패합니다. 예를 들어,

> library(plyr)
> x <- data.frame(hundreds = 7:9, tens = 1:3, ones = 4:6)
> mdply(x, function(tens, ones) { 10 * tens + ones })
Error in (function (tens, ones)  : unused argument (hundreds = 7)

@ user20877984의 답변이 우수합니다. 그들이 그것을 나의 이전의 대답보다 훨씬 더 잘 요약했기 때문에, 개념의 응용에서의 나의 (명백하게 여전히 장난스런) 시도가 여기있다 :

do.call 을 기본 방식으로 사용하기 :

powvalues <- list(power=0.9,delta=2)
do.call(power.t.test,powvalues)

전체 데이터 세트 작업 :

# get the example data
df <- data.frame(delta=c(1,1,2,2), power=c(.90,.85,.75,.45))

#> df
#  delta power
#1     1  0.90
#2     1  0.85
#3     2  0.75
#4     2  0.45

lapply 함수를 지정된 값의 각 행에 적용합니다.

result <- lapply(
  split(df,1:nrow(df)),
  function(x) do.call(power.t.test,x)
)

> str(result)
List of 4
 $ 1:List of 8
  ..$ n          : num 22
  ..$ delta      : num 1
  ..$ sd         : num 1
  ..$ sig.level  : num 0.05
  ..$ power      : num 0.9
  ..$ alternative: chr "two.sided"
  ..$ note       : chr "n is number in *each* group"
  ..$ method     : chr "Two-sample t test power calculation"
  ..- attr(*, "class")= chr "power.htest"
 $ 2:List of 8
  ..$ n          : num 19
  ..$ delta      : num 1
  ..$ sd         : num 1
  ..$ sig.level  : num 0.05
  ..$ power      : num 0.85
... ...

나는 여기에 존재하는 것을 알고있는 tidyverse 기능 이름을 tidyverse 했다. 앞으로 참조 할 사람과 tidyverse 매니아를 위해 다음을 추가하십시오. purrrlyr:invoke_rows ( purrr:invoke_rows 이전 버전에서는 purrr:invoke_rows ).

원래의 질문처럼 표준 통계 방법에 연결하면 broom 패키지가 도움이 될 것입니다.


다른 사람들은 mapply 가이 목적을 위해 만들어 mapply 올바르게 지적했지만, (완전성을 위해) 개념적으로 더 간단한 방법은 for 루프를 사용하는 것 for .

for (row in 1:nrow(df)) { 
    df$newvar[row] <- testFunc(df$x[row], df$z[row]) 
}

많은 함수가 이미 벡터화되어 있으므로 반복 (반복 또는 *pply 함수는 필요 없음)이 필요하지 않습니다. testFunc 는 그러한 예입니다. 당신은 간단하게 전화 할 수 있습니다 :

  testFunc(df[, "x"], df[, "z"])

일반적으로 그러한 벡터화 접근법을 먼저 시도하여 원하는 결과를 얻는 지 확인하는 것이 좋습니다.

또는 벡터화되지 않은 함수에 여러 인수를 전달해야하는 경우 mapplymapply 것일 수 있습니다.

  mapply(power.t.test, df[, "x"], df[, "z"])

원본 데이터의 하위 집합에 적용 apply 수 있습니다.

 dat <- data.frame(x=c(1,2), y=c(3,4), z=c(5,6))
 apply(dat[,c('x','z')], 1, function(x) sum(x) )

또는 함수가 합계 벡터화 된 버전을 사용하는 경우 :

rowSums(dat[,c('x','z')])
[1] 6 8

testFunc 를 사용 testFunc

 testFunc <- function(a, b) a + b
 apply(dat[,c('x','z')], 1, function(x) testFunc(x[1],x[2]))

편집 이름이 아닌 인덱스를 액세스하려면 다음과 같이 할 수 있습니다.

 testFunc <- function(a, b) a + b
 apply(dat[,c('x','z')], 1, function(y) testFunc(y['z'],y['x']))

mapply 사용

> df <- data.frame(x=c(1,2), y=c(3,4), z=c(5,6))
> df
  x y z
1 1 3 5
2 2 4 6
> mapply(function(x,y) x+y, df$x, df$z)
[1] 6 8

> cbind(df,f = mapply(function(x,y) x+y, df$x, df$z) )
  x y z f
1 1 3 5 6
2 2 4 6 8




dataframe