수색…


행 작업

R 코드를 벡터화 할 때 핵심은 R 함수의 "행 연산"또는 메소드 디스 패칭을 줄이거 나 없애는 것입니다.

즉, 언뜻보기에 각 행의 평균을 계산하는 것과 같은 "행 조작 별"이 필요한 문제에 접근 할 때 스스로에게 질문해야합니다.

  • 내가 다루고있는 데이터 세트의 클래스는 무엇입니까?
  • R 함수를 반복적으로 평가할 필요없이이를 수행 할 수있는 기존의 컴파일 된 코드가 있습니까?
  • 그렇지 않은 경우 행 대신 열을 사용하여 이러한 작업을 수행 할 수 있습니까?
  • 마지막으로 간단한 apply 루프를 실행하는 대신 복잡한 벡터화 된 코드를 개발하는 데 많은 시간을 할애 할 가치가 있습니까? 즉, R이 단순 루프를 사용하여 효율적으로 처리 할 수 ​​없을 정도로 데이터가 크고 정교합니까?

메모리 사전 할당 문제와 증가하는 객체를 루프에 넣는 대신, apply 루프, 메소드 디스 패칭 또는 루프 내 R 함수 재평가를 피하는 방법에 대해이 예제에 중점을 둘 것입니다.

행별로 평균을 계산하는 표준 / 쉬운 방법은 다음과 같습니다.

apply(mtcars, 1, mean)
          Mazda RX4       Mazda RX4 Wag          Datsun 710      Hornet 4 Drive   Hornet Sportabout             Valiant          Duster 360 
           29.90727            29.98136            23.59818            38.73955            53.66455            35.04909            59.72000 
          Merc 240D            Merc 230            Merc 280           Merc 280C          Merc 450SE          Merc 450SL         Merc 450SLC 
           24.63455            27.23364            31.86000            31.78727            46.43091            46.50000            46.35000 
 Cadillac Fleetwood Lincoln Continental   Chrysler Imperial            Fiat 128         Honda Civic      Toyota Corolla       Toyota Corona 
           66.23273            66.05855            65.97227            19.44091            17.74227            18.81409            24.88864 
   Dodge Challenger         AMC Javelin          Camaro Z28    Pontiac Firebird           Fiat X1-9       Porsche 914-2        Lotus Europa 
           47.24091            46.00773            58.75273            57.37955            18.92864            24.77909            24.88027 
     Ford Pantera L        Ferrari Dino       Maserati Bora          Volvo 142E 
           60.97182            34.50818            63.15545            26.26273 

하지만 우리가 잘 할 수 있을까요? 여기서 일어난 일을 볼 수 있습니다.

  1. 먼저 data.framematrix 로 변환했습니다. (그의 함수는 apply 함수 내에서 발생합니다.) 이것은 비효율적이며 위험합니다. matrix 은 한 번에 여러 개의 열 유형을 보유 할 수 없습니다. 따라서 이러한 변환은 정보 손실을 유발하고 결과를 오도 apply(iris, 2, class) str(iris) 또는 sapply(iris, class)apply(iris, 2, class) 비교하십시오.
  2. 둘째, 각 행에 대해 한 번씩 반복적으로 작업을 수행했습니다. 의미, 우리는 어떤 R 함수 nrow(mtcars) 시간을 평가해야했습니다. 이 특별한 경우 mean 은 계산 비용이 많이 드는 함수가 아니므로 큰 데이터 세트에서도 R이 쉽게 처리 할 수 ​​있지만 값이 큰 제곱근 연산과 관련된 행별로 표준 편차를 계산해야하는 경우 어떻게 될까요? ? 다음 포인트로 우리를 안내합니다 :
  3. 우리는 R 함수를 여러 번 평가했지만, 이미이 연산의 컴파일 된 버전이 있습니까?

사실 우리는 단순히 다음과 같이 할 수 있습니다 :

rowMeans(mtcars)
          Mazda RX4       Mazda RX4 Wag          Datsun 710      Hornet 4 Drive   Hornet Sportabout             Valiant          Duster 360 
           29.90727            29.98136            23.59818            38.73955            53.66455            35.04909            59.72000 
          Merc 240D            Merc 230            Merc 280           Merc 280C          Merc 450SE          Merc 450SL         Merc 450SLC 
           24.63455            27.23364            31.86000            31.78727            46.43091            46.50000            46.35000 
 Cadillac Fleetwood Lincoln Continental   Chrysler Imperial            Fiat 128         Honda Civic      Toyota Corolla       Toyota Corona 
           66.23273            66.05855            65.97227            19.44091            17.74227            18.81409            24.88864 
   Dodge Challenger         AMC Javelin          Camaro Z28    Pontiac Firebird           Fiat X1-9       Porsche 914-2        Lotus Europa 
           47.24091            46.00773            58.75273            57.37955            18.92864            24.77909            24.88027 
     Ford Pantera L        Ferrari Dino       Maserati Bora          Volvo 142E 
           60.97182            34.50818            63.15545            26.26273 

이것은 행 조작에 의한 것이 아니기 때문에 R 기능을 반복적으로 평가하지 않습니다. 그러나 우리는 여전히 data.framematrix 로 변환했습니다. rowMeans 에는 오류 처리 메커니즘이 있지만 처리 할 수없는 데이터 세트에서는 실행되지 않지만 효율성 비용이 여전히 있습니다.

rowMeans(iris)
Error in rowMeans(iris) : 'x' must be numeric

하지만 여전히 더 잘 할 수 있을까요? 우리는 대신에 오류 처리, 우리가 사용할 수 있도록하는 다른 방법으로 매트릭스 변환을 시도 할 수 mtcars (A 때문에 벡터로 data.frame 본질적이고 listlist A는 vector ).

Reduce(`+`, mtcars)/ncol(mtcars)
 [1] 29.90727 29.98136 23.59818 38.73955 53.66455 35.04909 59.72000 24.63455 27.23364 31.86000 31.78727 46.43091 46.50000 46.35000 66.23273 66.05855
[17] 65.97227 19.44091 17.74227 18.81409 24.88864 47.24091 46.00773 58.75273 57.37955 18.92864 24.77909 24.88027 60.97182 34.50818 63.15545 26.26273

이제 속도 향상을 위해 열 이름과 오류 처리 ( NA 처리 포함)가 손실되었습니다.


또 다른 예는 우리가 시도 할 수있는 기초 R을 사용하여 그룹별로 평균을 계산하는 것입니다.

aggregate(. ~ cyl, mtcars, mean)
cyl      mpg     disp        hp     drat       wt     qsec        vs        am     gear     carb
1   4 26.66364 105.1364  82.63636 4.070909 2.285727 19.13727 0.9090909 0.7272727 4.090909 1.545455
2   6 19.74286 183.3143 122.28571 3.585714 3.117143 17.97714 0.5714286 0.4285714 3.857143 3.428571
3   8 15.10000 353.1000 209.21429 3.229286 3.999214 16.77214 0.0000000 0.1428571 3.285714 3.500000

여전히 우리는 루프에서 R 함수를 평가하고 있지만 루프는 내부 ​​C 함수에 숨겨져 있습니다 (C 또는 R 루프인지는 중요하지 않습니다).

우리가 그것을 피할 수 있을까요? R에 rowsum 이라고하는 컴파일 된 함수가 rowsum , 다음과 같이 할 수 있습니다.

rowsum(mtcars[-2], mtcars$cyl)/table(mtcars$cyl)
mpg     disp        hp     drat       wt     qsec        vs        am     gear     carb
4 26.66364 105.1364  82.63636 4.070909 2.285727 19.13727 0.9090909 0.7272727 4.090909 1.545455
6 19.74286 183.3143 122.28571 3.585714 3.117143 17.97714 0.5714286 0.4285714 3.857143 3.428571
8 15.10000 353.1000 209.21429 3.229286 3.999214 16.77214 0.0000000 0.1428571 3.285714 3.500000

우리가 먼저 행렬로 전환해야했지만.

이 시점에서 우리는 현재 데이터 구조가 가장 적합한 것인지 질문 할 수 있습니다. data.frame 이 가장 좋은 방법입니까? 또는 효율을 높이기 위해 matrix 데이터 구조로 전환해야합니까?


매번 값 비싼 함수를 평가하기 시작할 때마다 행 연산이 점점 더 비싸집니다 (심지어 행렬에서도). 행 예제로 분산 계산을 고려해 보겠습니다.

우리가 행렬 m 을 가지고 있다고하자.

set.seed(100)
m <- matrix(sample(1e2), 10)
m
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    8   33   39   86   71  100   81   68   89    84
 [2,]   12   16   57   80   32   82   69   11   41    92
 [3,]   62   91   53   13   42   31   60   70   98    79
 [4,]   66   94   29   67   45   59   20   96   64     1
 [5,]   36   63   76    6   10   48   85   75   99     2
 [6,]   18    4   27   19   44   56   37   95   26    40
 [7,]    3   24   21   25   52   51   83   28   49    17
 [8,]   46    5   22   43   47   74   35   97   77    65
 [9,]   55   54   78   34   50   90   30   61   14    58
[10,]   88   73   38   15    9   72    7   93   23    87

하나는 간단히 할 수 있습니다 :

apply(m, 1, var)
[1]  871.6556  957.5111  699.2111  941.4333 1237.3333  641.8222  539.7889  759.4333  500.4889 1255.6111

한편, 분산의 공식을 따르면서이 연산을 완전히 벡터화 할 수 있습니다.

RowVar <- function(x) {
  rowSums((x - rowMeans(x))^2)/(dim(x)[2] - 1)
}
RowVar(m)
[1]  871.6556  957.5111  699.2111  941.4333 1237.3333  641.8222  539.7889  759.4333  500.4889 1255.6111


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow