こしあん
2020-05-23

ブロードキャストしたNumpy配列に代入するときにハマった話

Pocket
LINEで送る
Delicious にシェア

330{icon} {views}

書籍情報

技術書典8の新刊『モザイク除去から学ぶ 最先端のディープラーニング』(A4・195ページ)好評通販中です! 機械学習の入門からGANの最先端までを書いたおすすめの本となっています! Boothで試し読みできます。情報まとめ・質問用GitHub




Numpyのブロードキャストは便利ですが、ブロードキャストした配列に代入するときだけ思わぬ落とし穴があります。「ValueError: assignment destination is read-only」というエラーが出たとき、およびその解決方法を見ていきます。

発生した状況

環境:Numpy 1.18.3

Numpyのブロードキャストは値のコピー感覚で使えて便利です。明示的にブロードキャストするにはnp.broadcast_toという関数で出来ます。

例えば(0, 1, 2)というベクトルを作り、行方向に4回コピーするには、

import numpy as np

def main():
    x = np.arange(3).reshape(1, 3)
    x = np.broadcast_to(x, (4, 3))
    print(x)
    # [[0 1 2]
    #  [0 1 2]
    #  [0 1 2]
    #  [0 1 2]]

if __name__ == "__main__":
    main()

とします。ただしブロードキャストキャストした配列に値を代入しようとするとハマり、

def main():
    x = np.arange(3).reshape(1, 3)
    x = np.broadcast_to(x, (4, 3))
    x[:, 0] = np.arange(4) # これはエラー
    print(x)
    x[:, 0] = np.arange(4)
ValueError: assignment destination is read-only

と怒られてしまいます。

イミュータブルな配列に強引に書き込む方法

結論からいうとこれはダメなやり方です。np.broadcast_toの結果はイミュータブル(書き込み禁止)になっているので、書き込み禁止フラグを外してしまえば代入できます。

書き込み禁止フラグを外すには「x.flags.writeable = True」とすればいいです。ただの数値の代入なら一見うまく行っているように見えます。

def main():
    x = np.arange(3).reshape(1, 3)
    x = np.broadcast_to(x, (4, 3))
    x.flags.writeable = True  # 書き込み禁止を強引に外す
    x[:, 0] = 5
    print(x)
    #[[5 1 2]
    # [5 1 2]
    # [5 1 2]
    # [5 1 2]]

ただし、ブロードキャストした配列に、ベクトルを代入しようとすると正常な動作になりません

def main():
    x = np.arange(3).reshape(1, 3)
    x = np.broadcast_to(x, (4, 3))
    x.flags.writeable = True  # 書き込み禁止を強引に外す
    x[:, 0] = np.arange(4) # ベクトルの代入はおかしくなる
    print(x)
    #[[3 1 2]
    # [3 1 2]
    # [3 1 2]
    # [3 1 2]]

「np.arange(4)」の最後の値が全ての行にコピーされてしまいました。あくまでブロードキャストはブロードキャスト前の配列の参照をコピーしているのであって、値まではコピーしていないということでしょう。

書き込み禁止を外すのではなく配列をコピーする

ベクトルでも正常に動作するには、ブロードキャストした配列をコピーをします。「.copy()」というメソッドを使えばいいです。

def main():
    x = np.arange(3).reshape(1, 3)
    x = np.broadcast_to(x, (4, 3)).copy() # コピーする
    x[:, 0] = np.arange(4) # ベクトルの代入でも正常
    print(x)
    #[[0 1 2]
    # [1 1 2]
    # [2 1 2]
    # [3 1 2]]

ブロードキャストした配列を四則演算するときは内部的にコピーされているのでこのような配慮はいりませんが、代入するときだけ注意が必要です。



サークルからのお知らせ

Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」では、技術書・その他の本のごったまぜ通販をしています! 大人気のモザイク除去から北の駅巡りまでごちゃごちゃ感をお楽しみください!

技術書コーナー

(1) モザイク除去から学ぶ最先端のディープラーニング

技術書典8の新刊『モザイク除去から学ぶ 最先端のディープラーニング』好評通販中(A4・195ページ)です! Boothから試し読みできます!

(2) Shikoan's ML Blog

このブログが電子書籍になりました! 1冊オムニバス形式で200P超の大ボリューム。どこから読んでもOKなので、ぜひ通勤・通学のお供にどうぞ。

北の鉄道コーナー

Vol.1:日高本線 車なし全駅巡り


Pocket
LINEで送る
Delicious にシェア

Add a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です