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

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

ただいまの
回答率

88.80%

pythonプログラムの高速化

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 532

kak

score 23

いつも勉強させていただいてます。
AnacondaのPython3の環境下で以下のプログラムを実行しています。

カレントディレクトリに以下のようなカラムが2列あるtest.csvがあります。
各columnのindex0に'sample1','sample2'、index1以降にデータが247個入っています。
まず、test.csvのcolumn0,1をそれぞれの数値がそれぞれのカラムに入るように11列に分け、index1-247をそれぞれsample1.csv,sample2.csv...sample247.csvとして保存します。

0  
0                                                           sample1
1     VAL  H  1  103.30  68.2  76.95  67.3  26.35  70.9  76.95  66.6  26.35  73.3
2     VAL  H  2  103.30  68.2  76.95  67.3  26.35  70.9  76.95  66.6  26.35  73.3
3     VAL  H  3  103.30  68.2  76.95  67.3  26.35  70.9  76.95  66.6  26.35  73.3
4     VAL  H  4  103.30  68.2  76.95  67.3  26.35  70.9  76.95  66.6  26.35  73.3

...   ... .. ..     ...   ...    ...   ...    ...   ...    ...   ...    ...   ...
3     VAL  H 246  103.30  68.2  76.95  67.3  26.35  70.9  76.95  66.6  26.35  73.3
4     VAL  H 247  103.30  68.2  76.95  67.3  26.35  70.9  76.95  66.6  26.35  73.3

sample*.csvの左端に以下のtest.csvのindex0の2列を縦に挿入。

0              1
0                                                                       
NaN   sample1        sample2

以下のような形になります。

0      1   2   3     4      5     6          9   10     11    12  13
1       sample1  ASP  H  112 -20.93 -14.9  ...  -18.97 -50.3  -1.96  -3.9 -18.98 
2    sample2  ASP  H  112 -20.93 -14.9  ...  -18.97 -50.3  -1.96  -3.9 -18.98 

この一つのCSVファイル中でindex2のカラム4~13の値がindex1にあるsample1のそれぞれの数値と異なる数値を含む行のみ取り出し、この処理をカレントディレクトリにあるsample.csvファイルすべてで行い、一つのファイルで出力したいと思っています。
以下のようなプログラムを作成し、目的の値は得られましたが、時間がかかりました。

import pandas as pd
df_test=pd.read_csv("../test.csv",sep=",",header=None,index_col=0)  
for t in range(1,3):    
     sample_files=pd.read_csv("sample%s.csv" % (t),sep=",",index_col=0)    
     test_id=pd.concat([df_test.iloc[0,:],sample_files],axis=1)   
     df_frame=pd.DataFrame(test_id.iloc[0,:]).T  
     for i in range(1,247):     
          df_diff=test_id.iloc[i,4:]-test_id.iloc[0,4:]     
          df_diff_id=pd.concat([test_id.iloc[i,:4],df_diff])   
          for k in range(10):    
               if df_diff[k] !=0.0:                          
                     df_frame=df_frame.append(df_diff,ignore_index=True)
                     df_frame_unique=df_frame.drop_duplicates() 
                     df_frame_unique.to_csv("result.csv",sep=",")  
                     print(df_frame_unique) 

そこで以下の様にプログラムを修正し、目的のものが得られました。

df_result=pd.DataFrame() 
import pandas as pd
df_test=pd.read_csv("../test.csv",sep=",",header=None,index_col=0)  
for t in range(1,3):    
     sample_files=pd.read_csv("sample%s.csv" % (t),sep=",",index_col=0)    
     test_id=pd.concat([df_test.iloc[0,:],test_files],axis=1)   
     df_frame=pd.DataFrame(test_id.iloc[0,:]).T  
     for i in range(1,247):     
          df_diff=test_id.iloc[i,4:]-test_id.iloc[0,4:]     
          df_diff_id=pd.concat([df_test.iloc[i,:4],df_diff])   
          if df_diff.sum() ! = 0:                          
                     df_frame=df_frame.append(df_diff,ignore_index=True)
                     df_result=pd.concat([df_result,df_frame])
                     print(df_result)
                     df_result.to_csv("result.csv",sep=",") 


最初のプログラムで時間がかかり過ぎたのと一つのファイルで出力できていなかったので質問させて頂きましたが、質問を修正しているうちに2つ目のプログラムでよいことに気付きました。
ですが、折角ですので勉強のため、修正点やほかにもっといい方法があれば教えてください

ご指摘いただいたようにファイル出力をループの外にだして以下になりました。

df_result=pd.DataFrame() 
import pandas as pd
df_test=pd.read_csv("../test.csv",sep=",",header=None,index_col=0)  
for t in range(1,3):     
            sample_files=pd.read_csv("sample%s.csv" % (t),sep=",",index_col=0)    

            test_id=pd.concat([df_test.iloc[0,:],test_files],axis=1)    
            df_frame=pd.DataFrame(test_id.iloc[0,:]).T   
            for i in range(1,247): 
                 df_diff=test_id.iloc[i,4:]-test_id.iloc[0,4:]      
                 df_diff_id=pd.concat([df_test.iloc[i,:4],df_diff])    
                 if df_diff.sum() != 0:
                    df_frame=df_frame.append(df_diff,ignore_index=True).drop_duplicates()                

                    df_result=pd.concat([df_result,df_frame]) 
 print(df_result) 
 df_result.to_csv("result.csv",sep=",") 


ちなみに処理時間は以下の様でした。
第一ループ内で出力(for i in range(1,247)と同じインデント)
elapsed time:19.02880597114563
第2ループ内で出力(df_result=pd.concat...と同じインデント)
elapsed time:4.529508113861084
ループ外で出力
elapsed time:2.024280071258545

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • hayataka2049

    2019/04/17 21:57

    >df_testのリストを元に次々に取り込み

    >test_idによりサンプル名をtest_filesに追加
    など、それまでに説明されていない言葉が次々に出てきても理解できないです。率直に言って、読んでも何がしたいのかよくわからなかったです。説明を改善したほうが回答が得られやすいと思います。
    途中の過程はともかく、最終的にやりたいことはそれほど難しくないような気もするので、「どういうデータがあり、どういう結果が得たいのか」をできるだけ詳細に書いてください。また、データはDataFrameのprint結果のコピペではなく、CSVに書かれているテキストを載せた方が回答する側としてはありがたいです。

    キャンセル

  • kak

    2019/04/18 10:35

    ご指摘ありがとうございます。確かに自分で読み返してもよく分からない内容でした。
    失礼しました。質問内容を修正しながらプログラムを見直し、目的は達成できたように思います。
    ですが、もし見ていただけるなら改善点や他の方法を教えてください。

    キャンセル

回答 1

checkベストアンサー

0

  • 仕様がわからない

df_test_id等いくつかの変数が、未定義のまま使用されています。
>test*.csvが270個あります
>270個のsample.csv
→test*なのかsample*なのか?
→270個と仰っていますが、sample1890.csvと1890個ありそうなファイル名ですし、プログラム上も1890ファイル処理しているようです。
>一つのCSVファイル中でindex2~1890
→プログラム上では270行までしか処理していないようです。

  • ループ内でファイル出力

ファイル操作は基本的に重たい処理だと考えてください。しかし、プログラム2では最高1890*270回のファイル出力を行うかと思います。さらにプログラム1では10倍のファイル出力がありました。それは遅い筈です。
プログラム2では折角ループの外に結果データの宣言を移動したのですから、全てのデータを読み終わってループを抜けてから出力しましょう。

  • ループ内でconcatしているとこ

df_frameはループ毎に値が増えていき、df_resultに連結されていきます。次ループの時、既に入っている値を再度入れてしまうことになります。
つまりは以下のような処理が行われています。

import pandas as pd
df_result = pd.DataFrame() 
df_frame = pd.DataFrame([1])# 1行目が入ってる

# ループ1回目
df_frame = df_frame.append([2])# 2行目
df_result = pd.concat([df_result,df_frame])
print(df_result)
'''
   0
0  1
0  2
'''

# ループ2回目
df_frame = df_frame.append([3])# 2行目
df_result = pd.concat([df_result,df_frame])
print(df_result)
'''
   0
0  1
0  2
0  1
0  2
0  3
'''


まずファイル毎の結果をdf_frameに格納していきます。その後、"内側のループが終わった後"にdf_resultに連結してあげたらいいと思います。
ループ内の処理は最小限にするのが基本です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/04/23 21:32

    遅くなりました。ファイルが消えてしまったので少ないサンプルで作り直してプログラムを修正しました。printで途中経過を見ていた内容がまさにご指摘いただいた通りでした。お陰様でかなりスピードアップ出来ました。ありがとうございました。

    キャンセル

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

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

関連した質問

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