質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.34%

Python3: listよりnumpy.ndarrayのほうが処理が遅くなることもあるのかどうか

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 406
退会済みユーザー

退会済みユーザー

具体的なコードの質問というよりは抽象的な質問です。

・要約した質問
Pythonで「listよりnumpy.ndarrayのほうが処理が速い」というのは、必ずしもそうだとも言えないのか。

・質問とその背景
Pythonで数独パズルを解くプログラムを書きました。問題の盤面を9×9のリスト形式(下コードのような形)で与えると、それについて解いてくれるものです。

#問題の例
#0は空白マスを表す
sudoku_problem = [[0,0,5,3,0,0,0,0,0],
                  [8,0,0,0,0,0,0,2,0],
                  [0,7,0,0,1,0,5,0,0],
                  [4,0,0,0,0,5,3,0,0],
                  [0,1,0,0,7,0,0,0,6],
                  [0,0,3,2,0,0,0,8,0],
                  [0,6,0,5,0,0,0,0,9],
                  [0,0,4,0,0,0,0,3,0],
                  [0,0,0,0,0,9,7,0,0]]
#「世界一難しい数独」で調べると出てくる問題です。


上記の問題だと約1.5秒で解いてくれます。

ひとまずプログラムが完成したので、次はこれを高速化しようとしました。
完成したプログラムではpythonのリストオブジェクトを多用しているのですが、「pythonのリストの操作は処理が遅い、データ型の決まっているnumpy.ndarrayを使ったほうが高速」のような話を聞いていたので、プログラムの内問題の盤面とそれに関する処理をすべてnumpy.ndarrayの形式に書き換えました。

#問題の入力形式をnumpy.ndarrayに変えた
import numpy as np
sudoku_problem = np.array([[0,0,5,3,0,0,0,0,0],
                           [8,0,0,0,0,0,0,2,0],
                           [0,7,0,0,1,0,5,0,0],
                           [4,0,0,0,0,5,3,0,0],
                           [0,1,0,0,7,0,0,0,6],
                           [0,0,3,2,0,0,0,8,0],
                           [0,6,0,5,0,0,0,0,9],
                           [0,0,4,0,0,0,0,3,0],
                           [0,0,0,0,0,9,7,0,0]], dtype='int8')


しかし、そうしてできたプログラムを実行してみると、処理にかかる時間が元のプログラムより30倍ほど長くなってしまいました。
もともとのプログラムがfor文をガンガン回す感じもので、その構造については変更後もほぼかえていないので「あんまり早くならないかもな」ぐらいに思っていたのですが、
numpy.ndarrayの処理は普通のリストより早くなるものだと思っていたので大幅に遅くなったことが意外でした。

例えば行列計算なんかの処理をガンガンやる場合には、numpyを使うとデータ型は固定だしfor文をあまり書かなくて済むので高速になる、というのは多分あってると思うのですが、
そういう処理をやらない場合、numpyは単なるlist型の上位互換としては見ないほうがいいということでしょうか。

ぼんやりした質問で申し訳ないですがどなたか意見をくださると幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

普通にpythonレイヤからnumpy配列の「要素」にアクセスするような処理をすると、オーバーヘッドの塊みたいなものですから遅いでしょうねえ。

import timeit
import numpy as np

n = 2
L = [[0 for _ in range(10**n)] for _ in range(10**n)]
A = np.array(L)

def func1(a):
    for i in range(10**n):
        for j in range(10**n):
            a[i][j]

def func2(a):
    for i in range(10**n):
        for j in range(10**n):
            a[i,j]

print(timeit.timeit(lambda :func1(L), number=100))
print(timeit.timeit(lambda :func1(A), number=100))
print(timeit.timeit(lambda :func2(A), number=100))
""" =>
0.0637162079801783
0.2254948549962137
0.14580219899653457
"""

実装についていえば、numpy配列は、C配列のwrapperみたいなものです。要素の取り出しはメモリ上のデータに対応する値を持つpythonオブジェクトを生成して返しますし、代入はその逆(pythonオブジェクトをデータに変換して書き込む)です。listはそんなまどころっこしいことはしていなくて、要素はただのpythonオブジェクトへのポインタです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る