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

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

ただいまの
回答率

88.61%

cythonでfor文を速くしたい

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,982

kohekoh

score 136

以下のようなコードがあります

import nltk

def tfidf(word):
    collection = nltk.TextCollection(word) #サイトにのっていた
    doc = []
    cdef float a
    cdef str term
    for do in word:
          wo=[]
          for term in set(do):
              a = collection.tf_idf(term, do)
              if(a > 0):
                  wo.append([term,a]) #ここも上のサイトにのってる
                  #print(wo)
          wo.sort(key=lambda x:x[1]) #keyに無名関数lambdaをいれてる woの1番目の要素(WO(1,2)だったら”2”)でソート
          wo.reverse()
          #print(wo)
          slice1 = [i[0] for i in wo] #woの単語のみを抽出
          lists = slice1[:20] #20番までにへらす
          doc.append(list(lists)) #listsが文字列だから、リストに格納
          del wo

    return doc


wordは
[["aa"],["bb"],["af"],["df"],["fd"]]
のような文字列のリストです

現状このようなコードでcython化させているのですが
全然はやくなりません
そもそもほかの部分に冗長があったりするのかもしれませんが
型定義などで速くする方法はありますか?
この処理が遅くしているなどの指摘でもかまわないので
よろしくお願いします

修正依頼をうけて-----------------
処理時間の変化はやる時々でかわるのですが
それこそ誤差程度で、1秒以内で速くなったり、遅くなったりを
繰り返しています

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2017/07/27 12:39

    >現状このようなコードでcython化させているのですが 全然はやくなりません 私にはできませんが、cython化前後で時間がどれくらい変わったか(変わっていないか)の数字があると、わかる人には答えがわかるかもしれません。

    キャンセル

回答 4

checkベストアンサー

+3

一度プロファイラーなどを使用して、現状のコードを解析してみることをお勧めします。

参考までに、私の環境で(Cython版)tfidf関数をcProfileで解析してみたところ、下記のような結果になっております。(5MByteくらいのデータを使用)

6307418 function calls in 10.835 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   10.835   10.835 {built-in method builtins.exec}
        1    0.038    0.038   10.835   10.835 <string>:1(<module>)
        1    0.298    0.298   10.797   10.797 {tfidf.tfidf}
   674820    0.528    0.000   10.026    0.000 text.py:581(tf_idf)
   674820    0.220    0.000    8.836    0.000 text.py:568(idf)
      538    8.514    0.016    8.514    0.016 text.py:575(<listcomp>)
   674820    0.255    0.000    0.662    0.000 text.py:564(tf)
        1    0.001    0.001    0.472    0.472 text.py:556(__init__)
        1    0.044    0.044    0.472    0.472 text.py:289(__init__)
   674820    0.377    0.000    0.377    0.000 {method 'count' of 'list' objects}
   ()

この結果を見る限りは、tfidf関数全体(tfidf.tfidf) でかかった時間(cumtime) 10.797秒に対して、nltkのtf_idf()内で費やした時間は 10.026秒となっており、この外部ライブラリでの処理時間がほぼ支配的になっております。

ですので、いくらCythonの型を最適化してtfidf関数内のループを速くしても、それほど効果がないきがします。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/07/27 21:19

    ありがとうございます!

    キャンセル

  • 2017/07/27 21:32

    処理を早くするには、やはりtfidfの部分を速くなるように自分で書き直すくらいしかないですかね?

    キャンセル

+2

おそらく上のコードでの処理時間の大半を占めるのはnltkのtf-idfの計算の部分だと思います。(手元で確認はしていないので例え話ですが)全体の数%程度の負荷の処理を100倍早くしても全体の処理時間に対する改善は微々たるものですよね。

パフォーマンスチューニングで大切なのは闇雲な最適化ではなく計測です。ボトルネックになっている箇所を把握することができていますか?

例えば、あげられているような短いコード片に対してはline_profilerなどを使って見ると良いかもしれません。行単位でのプロファイルの結果が見れるのでおおよその見当はつくのではないかと思います。

そして、tf-idf自体の実装はそれほど複雑ではないので自分で早い実装を書いてみると良いと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/07/27 21:19

    なるほど
    ありがとうございます!

    キャンセル

+1

ちなみにですが、
gensimを用いてtfidfをしたら断然早くなりました
ありがとうございました

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

Pythonはやったことは無いんですが、興味本位で検索したら、以下のような記事がありました。

深入りしないCython入門

高速化においては型定義が結構重要なんですね。

なので、入力パラメータの型宣言と後は配列はNumPy 配列を使用すること位でしょうか。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/07/27 21:38

    解決に役立たない

    キャンセル

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

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

関連した質問

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