web-dev-qa-db-ja.com

pandas dataframeをメモリ内のファイルのようなオブジェクトに変換しますか?

私は毎日約2〜250万レコードをPostgresデータベースにロードしています。

次に、pd.read_sqlを使用してこのデータを読み取り、データフレームに変換してから、列の操作と小さなマージを行います。他の人が使用できるように、この変更されたデータを別のテーブルとして保存しています。

私がpd.to_sqlを実行すると、時間がかかります。 csvファイルを保存してPostgresでCOPY FROMを使用すると、全体が数分しかかかりませんが、サーバーが別のマシン上にあり、そこにファイルを転送するのは面倒です。

Psycopg2を使用すると、copy_expertを使用して一括コピーのメリットを享受できるように見えますが、それでもpythonを使用しています。できれば、実際のcsvファイルの作成は避けたいです。 pandas dataframeを使用してメモリでこれを行うことはできますか?

これが私のpandasコードの例です。copy_expertなどを追加して、可能であればこのデータをより速く保存できるようにしたいと考えています。

    for date in required_date_range:
        df = pd.read_sql(sql=query, con=pg_engine, params={'x' : date})
        ...
        do stuff to the columns
        ...
        df.to_sql('table_name', pg_engine, index=False, if_exists='append',  dtype=final_table_dtypes)

誰かがサンプルコードで私を助けてくれますか?私はpandasを引き続き使用することを好み、メモリ内でそれを実行するのは良いことです。そうでない場合は、csv一時ファイルを作成し、その方法で実行します。

編集-ここに私の最終的なコードがあります。数時間ではなく、日付あたり数百秒(数百万行)しかかかりません。

to_sql = "" "CSVヘッダーのあるSTDINから%sをコピー" ""

def process_file(conn, table_name, file_object):
    fake_conn = cms_dtypes.pg_engine.raw_connection()
    fake_cur = fake_conn.cursor()
    fake_cur.copy_expert(sql=to_sql % table_name, file=file_object)
    fake_conn.commit()
    fake_cur.close()


#after doing stuff to the dataframe
    s_buf = io.StringIO()
    df.to_csv(s_buf) 
    process_file(cms_dtypes.pg_engine, 'fact_cms_employee', s_buf)
14
trench

Pythonモジュールiodocs )には、ファイルのようなオブジェクトに必要なツールがあります。

import io

# text buffer
s_buf = io.StringIO()

# saving a data frame to a buffer (same as with a regular file):
df.to_csv(s_buf)

編集します。(忘れました)後でバッファから読み取るには、その位置を先頭に設定する必要があります。

s_buf.seek(0)

psycopg2だが docs によるとcopy_expertおよびcopy_fromを使用できます。例:

cur.copy_from(s_buf, table)

(Python 2については StringIO を参照してください。)

27
ptrj

Ptrjからのソリューションの実装に問題がありました。

問題は、pandasバッファの位置を最後に設定することから生じていると思います。

以下を参照してください。

from StringIO import StringIO
df = pd.DataFrame({"name":['foo','bar'],"id":[1,2]})
s_buf = StringIO()
df.to_csv(s_buf)
s_buf.__dict__

# Output
# {'softspace': 0, 'buflist': ['foo,1\n', 'bar,2\n'], 'pos': 12, 'len': 12, 'closed': False, 'buf': ''}

Posが12であることに注意してください。後続のcopy_fromコマンドが機能するためには、posを0に設定する必要がありました。

s_buf.pos = 0
cur = conn.cursor()
cur.copy_from(s_buf, tablename, sep=',')
conn.commit()
5
a_bigbadwolf