답변:
이것이 스위프와 스케일을위한 것입니다.
sweep(m, 2, colSums(m), FUN="/")
scale(m, center=FALSE, scale=colSums(m))
또는 재활용을 사용할 수 있지만 두 번 재 이동해야합니다.
t(t(m)/colSums(m))
또는 질문에서했던 것처럼 나누려는 전체 행렬을 구성 할 수 있습니다. 여기 또 다른 방법이 있습니다.
m/colSums(m)[col(m)]
그리고 주석에서 caracal의 추가 사항을 주목하십시오.
m %*% diag(1/colSums(m))
내부적으로 사용하는 또 다른 방법은 prop.table(m, 2)
간단 propr(m)
합니다 sweep
.
이러한 동등한 솔루션의 성능을 비교하는 것이 흥미로울 수 있으므로 microbenchmark
패키지를 사용하여 약간의 벤치 마크를 수행했습니다 .
이것은 m
내가 사용한 입력 행렬입니다 .
[,1] [,2] [,3] [,4] [,5]
A 1.831564e-02 4.978707e-02 1.353353e-01 3.678794e-01 3.678794e-01
B 3.678794e-01 1.353353e-01 4.978707e-02 1.831564e-02 6.737947e-03
C 4.539993e-05 2.061154e-09 9.357623e-14 4.248354e-18 5.242886e-22
D 1.831564e-02 4.978707e-02 1.353353e-01 3.678794e-01 3.678794e-01
E 3.678794e-01 1.353353e-01 4.978707e-02 1.831564e-02 6.737947e-03
F 4.539993e-05 2.061154e-09 9.357623e-14 4.248354e-18 5.242886e-22
G 1.831564e-02 4.978707e-02 1.353353e-01 3.678794e-01 3.678794e-01
H 3.678794e-01 1.353353e-01 4.978707e-02 1.831564e-02 6.737947e-03
I 4.539993e-05 2.061154e-09 9.357623e-14 4.248354e-18 5.242886e-22
이것은 벤치 마크 설정입니다 :
microbenchmark(
prop = prop.table(m, 2),
scale = scale(m, center=FALSE, scale=colSums(m)),
sweep = sweep(m, 2, colSums(m), FUN="/"),
t_t_colsums = t(t(m)/colSums(m)),
m_colsums_col = m/colSums(m)[col(m)],
m_mult_diag = m %*% diag(1/colSums(m)),
times = 1500L)
벤치 마크 결과는 다음과 같습니다.
Unit: microseconds
expr min lq median uq max
1 m_colsums_col 29.089 32.9565 35.9870 37.5215 1547.972
2 m_mult_diag 43.278 47.6115 51.7075 53.8945 110.560
3 prop 207.070 214.3010 216.6800 219.9680 2091.913
4 scale 133.659 142.6325 145.3100 147.9195 1730.640
5 sweep 113.969 119.6315 121.3725 123.6570 1663.356
6 t_t_colsums 56.976 65.3580 67.8895 69.5130 1640.660
완전성을 위해 다음이 출력됩니다.
[,1] [,2] [,3] [,4] [,5]
A 1.580677e-02 8.964714e-02 2.436862e-01 3.175247e-01 3.273379e-01
B 3.174874e-01 2.436862e-01 8.964714e-02 1.580862e-02 5.995403e-03
C 3.918106e-05 3.711336e-09 1.684944e-13 3.666847e-18 4.665103e-22
D 1.580677e-02 8.964714e-02 2.436862e-01 3.175247e-01 3.273379e-01
E 3.174874e-01 2.436862e-01 8.964714e-02 1.580862e-02 5.995403e-03
F 3.918106e-05 3.711336e-09 1.684944e-13 3.666847e-18 4.665103e-22
G 1.580677e-02 8.964714e-02 2.436862e-01 3.175247e-01 3.273379e-01
H 3.174874e-01 2.436862e-01 8.964714e-02 1.580862e-02 5.995403e-03
I 3.918106e-05 3.711336e-09 1.684944e-13 3.666847e-18 4.665103e-22
작은 행렬에 대한 의심의 여지없이 m / colSums(m)[col(m)]
승리 !
그러나 큰 행렬의 경우? 다음 예제에서는 1000x1000 매트릭스를 사용했습니다.
set.seed(42)
m <- matrix(sample(1:10, 1e6, TRUE), 1e3)
...
Unit: milliseconds
expr min lq median uq max
1 m_colsums_col 55.26442 58.94281 64.41691 102.69683 119.08685
2 m_mult_diag 34.67692 41.68494 80.05480 89.48099 99.72062
3 prop 87.95552 94.13143 99.17044 136.03669 160.51586
4 scale 52.84534 55.07107 60.57154 99.87761 156.16622
5 sweep 52.79542 55.93877 61.55066 99.67766 119.05134
6 t_t_colsums 63.09783 65.53783 68.93731 110.03691 127.89792
들어 큰 행렬의 m / colSums(m)[col(m)]
수행도 (4 위치)하지만 승리하지 않습니다 .
대한 큰 행렬의 m %*% diag(1/colSums(m))
승리 !
propr
됩니까?
apply(m,2,norm<-function(x){return (x/sum(x)}) ?
m %*% diag(1/colSums(m))