和風スパゲティのレシピ

日本語でコーディングするExcelVBA

Transpose関数と愚直な配列代入の速度比較

Transpose関数の実行速度が気になったので検証してみました。

同じ処理をFor文で全要素代入して再現した方法との速度比較で検証します。


一応経緯を説明しますと、Transpose関数には要素数65,536という上限が存在します。

この上限を超えた際に自作関数で対応する必要があるのですが、
「その関数を使うと遅くなってしまわないか?」
という検証を行ったものです。


Transpose関数の上限仕様についてはこちらの記事をご覧ください。
www.limecode.jp



さて検証結果ですが、お忙しい方向けに結論を先に書いておくと、

  • 愚直に配列に代入した方が高速
  • ただしどちらも十分高速なため誤差の範囲と捉えて良い

というのが結論でした。


検証内容を読みたい方は、以下読み進めてみてください。

一次元配列を二次元配列にする用途で使用する場合

一次元配列を縦方向にセル出力する際に↓のようなコードを使います。

始点セル.Resize(要素数, 1).Value = WorksheetFunction.Transpose(配列)

 
これをTransposeの上限65,536行以降で行う必要が出た際に、
自作関数にすることでTransposeより遅くなってしまわないかを検証します。

Sub Transpose関数vs愚直に配列代入_一次元配列→二次元配列()
    
    ' 50000連番の配列でテスト
    Dim Arr(1 To 50000)
    Dim i As Long
    For i = LBound(Arr) To UBound(Arr)
        Arr(i) = i
    Next
    
    Dim 開始時刻 As Double, 終了時刻 As Double
    開始時刻 = Timer

    Dim tmp
    For i = 1 To 500
        ' どちらかのコメントアウトを解いて実行
        'tmp = WorksheetFunction.Transpose(Arr)
        tmp = GetArray一次元配列→n行1列の二次元配列(Arr)
    Next
    
    終了時刻 = Timer
    Debug.Print "このマクロの実行時間:" & (終了時刻 - 開始時刻) & "秒"

End Sub

Function GetArray一次元配列→n行1列の二次元配列(Arr As Variant) As Variant
    
    Dim 生成配列()
    ReDim 生成配列(LBound(Arr) To UBound(Arr), 1 To 1)
    
    Dim i As Long
    For i = LBound(Arr) To UBound(Arr)
        生成配列(i, 1) = Arr(i)
    Next
    
    GetArray一次元配列→n行1列の二次元配列 = 生成配列
    
End Function

 
◆ 検証結果

Transpose関数 2.20703125秒
愚直な配列代入 1.208984375秒


実行時間を見ると、愚直に配列に代入した方が早いという結果になりました。


といっても50,000要素の変換処理を500回やってこの処理時間です。

よほどの規模のデータを相手にしない限りは、
どちらも十分高速で差は誤差の範囲」と捉えて良さそうですね。


一次元配列→二次元配列の変換コードにおいては、

  • Transpose上限対応関数を作ったら常にそれを使ってOK
  • 自作関数の無い状況下であればTranspose関数で十分高速

と結論しておきます。

二次元配列の行列入れ替えを実行する場合

続いて本来のTranspose関数の使い方になります。
こちらの速度比較は以下の通りでした。

Sub Transpose関数vs愚直に配列代入_二次元配列行列変換()
    
    ' 1000×1000の配列でテスト
    Dim Arr As Variant
    Arr = Worksheets("データ").Range("A1").Resize(10000, 20)
    
    Dim 開始時刻 As Double, 終了時刻 As Double
    開始時刻 = Timer

    Dim i As Long, tmp
    For i = 1 To 100
        'tmp = WorksheetFunction.Transpose(Arr)
        tmp = 愚直に代入するTranspose(Arr)
    Next
    
    終了時刻 = Timer
    Debug.Print "このマクロの実行時間:" & (終了時刻 - 開始時刻) & "秒"

End Sub

Function 愚直に代入するTranspose(Arr As Variant) As Variant
    
    Dim 生成配列()
    ReDim 生成配列(LBound(Arr, 2) To UBound(Arr, 2), LBound(Arr, 1) To UBound(Arr, 1))
    
    Dim i As Long
    Dim j As Long
    
    For i = LBound(Arr, 2) To UBound(Arr, 2)
        For j = LBound(Arr, 1) To UBound(Arr, 1)
            生成配列(i, j) = Arr(j, i)
        Next
    Next
    
    愚直に代入するTranspose = 生成配列
End Function

 
◆ 検証結果

Transpose関数 1.6199951171875秒
愚直な配列代入 1.0469970703125秒


こちらも愚直に配列に代入した方が早いという結果でしたね。


といっても10000×20の配列を100回変換してこれなので、
一次元配列変換と同じく「どちらも十分高速で差は誤差の範囲」です。

  • Transpose上限対応関数を作ったら常にそれを使ってOK
  • 自作関数の無い状況下であればTranspose関数で十分高速


という結論で変更ありません。



以上がTranspose関数 vs 愚直な配列代入の速度比較結果でした。


どちらも十分高速ですので、速度は気にする必要はなさそうです。

  • Transpose関数の要素数上限65,536への対応
  • その他データ型(Transposeは数値がDouble型限定)への対応

あたりに対応する場合は自作関数を用意し、
それ以外の場合はTranspose関数をそのまま使ってOKですね。