programing

각 행의 여러 인수를 사용하여 각 데이터 프레임 행에 적용 유사 함수 호출

muds 2023. 6. 25. 20:35
반응형

각 행의 여러 인수를 사용하여 각 데이터 프레임 행에 적용 유사 함수 호출

여러 개의 열이 있는 데이터 프레임이 있습니다.데이터 프레임의 각 행에 대해 해당 행의 함수를 호출하고, 해당 함수의 입력은 해당 행의 여러 열을 사용합니다.예를 들어, 이 데이터와 두 개의 인수를 허용하는 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

예를 들어 x열과 z열에 이 테스트 Func를 적용하려고 합니다.그래서 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

하지만 오류가 있어요, 아이디어 있어요?

EDIT: 제가 부르고 싶은 실제 기능은 단순한 합계가 아니라 power.t.t.test입니다.저는 a+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.t.t.test에 대한 출력 벡터입니다.

신청할 수 있습니다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 <- 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']))

A data.frame입니다.list그래서...

벡터화된 함수의 경우 do.call보통 좋은 내기입니다.하지만 논쟁의 이름이 등장합니다. 당신의 기여당입니다.testFunca와 b 대신에 args x와 y를 사용하여 호출됩니다....를 발생시키지 관련 를 전달할 수 합니다.

do.call( function(x,z,...) testFunc(x,z), df )

벡터화되지 않은 기능의 경우,mapply사용할 수 있지만, 인수의 순서와 일치하거나 명시적으로 이름을 지정해야 합니다.

mapply(testFunc, df$x, df$z)

은 씩끔가.apply모든 인수가 동일한 유형일 때처럼 강제로 작동합니다.data.frame행렬로 변환하면 데이터 유형이 변경되어 문제가 발생하지 않습니다.당신의 예는 이런 종류의 것이었습니다.

인수가 모두 전달되는 다른 함수 내에서 함수를 호출하려면 이들보다 훨씬 교묘한 방법이 있습니다.신체의 첫 번째 라인을 연구합니다.lm()당신이 그 길을 가고 싶다면요.

사용하다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

으로 새로운 :dplyr

적용할 함수가 벡터화된 경우 다음을 사용할 수 있습니다.mutatedplyr패키지:

> 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

그 는 저의겸의는로한으, 그일가적도는구한합장입니다.mdplyplyr꾸러미

예:

> 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)

다른 사람들은 올바르게 지적했습니다.mapply이 목적을 위해 만들어졌지만, (완전성을 위해) 개념적으로 더 간단한 방법은 단지 사용하는 것입니다.for 리고리고▁loop..

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

되어 있기 . (둘 다 많함가이벡필반없있습요다니가복할로으므어되미화터수은ither▁many없ne▁are다습니▁(필ationsization요▁need반가▁iter).for 또는 프루또는*pply함수)를 선택합니다.당신의.testFunc그러한 예 중 하나입니다.간단히 전화할 수 있습니다.

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

일반적으로 이러한 벡터화 접근 방식을 먼저 시도하고 원하는 결과가 나오는지 확인하는 것이 좋습니다.


해야 할 , "" "" "" "" "" "" "" " "" " " " " " " " " " " " " " " "mapply 있는 도 있습니다: 다과같은기사수용있할다습니능을음▁might다.

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

여기 다른 접근법이 있습니다.그것은 더 직관적입니다.

답변 중 일부를 고려하지 않은 것으로 생각되는 핵심 측면 중 하나는 나중에 사용자가 행 계산을 쉽게 수행할 수 있도록 하는 것입니다(). 행렬(모든 숫자) 데이터에 대해서만 적용할 수 있습니다.

데이터 프레임에 대해서는 여전히 열에 대한 작업이 가능합니다.

as.data.frame(lapply(df, myFunctionForColumn()))

행에서 작동하려면 먼저 전치를 수행합니다.

tdf<-as.data.frame(t(df))
as.data.frame(lapply(tdf, myFunctionForRow()))

단점은 R이 당신의 데이터 테이블을 복사할 것이라고 생각합니다.기억력 문제일 수도 있습니다.(이것은 정말 슬픈 일입니다. 왜냐하면 tdf가 원래 df에 대한 반복기이기 때문에 메모리를 절약할 수 있지만 R은 포인터나 반복기 참조를 허용하지 않기 때문입니다.)

또한 관련 질문은 데이터 프레임의 각 개별 셀에서 작동하는 방법입니다.

newdf <- as.data.frame(lapply(df, function(x) {sapply(x, myFunctionForEachCell()}))

data.table이를 위한 직관적인 방법도 있습니다.

library(data.table)

sample_fxn = function(x,y,z){
    return((x+y)*z)
}

df = data.table(A = 1:5,B=seq(2,10,2),C = 6:10)
> df
   A  B  C
1: 1  2  6
2: 2  4  7
3: 3  6  8
4: 4  8  9
5: 5 10 10

:= 안에 새할 수 .

df[,new_column := sample_fxn(A,B,C)]
> df
   A  B  C new_column
1: 1  2  6         18
2: 2  4  7         42
3: 3  6  8         72
4: 4  8  9        108
5: 5 10 10        150

또한 다음 방법을 사용하면 상수를 인수로 쉽게 받아들일 수 있습니다.

df[,new_column2 := sample_fxn(A,B,2)]

> df
   A  B  C new_column new_column2
1: 1  2  6         18           6
2: 2  4  7         42          12
3: 3  6  8         72          18
4: 4  8  9        108          24
5: 5 10 10        150          30

@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그자리의 power.t.test지정된 값의 각 행에 대한 함수:

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매니아:purrrlyr:invoke_rows(purrr:invoke_rows이전 버전에서는).

원래 질문과 같이 표준 통계 방법에 연결하면 브룸 패키지가 도움이 될 것입니다.

data.frame 열이 서로 다른 유형이면apply()문제가 있습니다.행 반복에 대한 미묘함은 다음과 같습니다.apply(a.data.frame, 1, ...)열이 서로 다른 유형(예: 요인 및 숫자 열)인 경우 암시적 형식을 문자 형식으로 변환합니다.다음은 하나의 열에 요인을 사용하여 숫자 열을 수정하는 예제입니다.

mean.height = list(BOY=69.5, GIRL=64.0)

subjects = data.frame(gender = factor(c("BOY", "GIRL", "GIRL", "BOY"))
         , height = c(71.0, 59.3, 62.1, 62.1))

apply(height, 1, function(x) x[2] - mean.height[[x[1]]])

열이 문자 형식으로 변환되기 때문에 뺄셈이 실패합니다.

한 가지 해결책은 두 번째 열을 숫자로 역변환하는 것입니다.

apply(subjects, 1, function(x) as.numeric(x[2]) - mean.height[[x[1]]])

그러나 열을 분리하고 사용하면 변환을 피할 수 있습니다.mapply():

mapply(function(x,y) y - mean.height[[x]], subjects$gender, subjects$height)

mapply()한 이유는 필한이유 때문입니다.[[ ]]벡터 인수를 사용할 수 없습니다.따라서 열 반복은 다음으로 벡터를 전달함으로써 뺄셈 전에 수행될 수 있습니다.[]조금 더 추악한 코드로:

subjects$height - unlist(mean.height[subjects$gender])

정말 은 이을위정좋기능은은말한입니다.adplyplyr특히 원본 데이터 프레임에 결과를 추가하려는 경우.와 그 인 이와함그사촌수▁and▁this사.ddply많은 두통과 코드 줄을 아꼈습니다!

df_appended <- adply(df, 1, mutate, sum=x+z)

또는 원하는 기능을 호출할 수 있습니다.

df_appended <- adply(df, 1, mutate, sum=testFunc(x,z))

언급URL : https://stackoverflow.com/questions/15059076/call-apply-like-function-on-each-row-of-dataframe-with-multiple-arguments-from-e

반응형