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

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

新規登録して質問してみよう
ただいま回答率
85.48%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1847閲覧

パイソン3 diff関数 メモリーエラー

osamu55

総合スコア12

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2019/02/06 03:56

前提・実現したいこと

パイソン3のdiff関数を活用し、以下のBook1.csvを用いて処理したいのですが、
100万行以上あるcsvデータで
処理するとメモリーエラーになります。

ここに質問の内容を詳しく書いてください。

Book1.csvに以下のファイルが入っています。

日付  品番 在庫
11-1  A  101
11-1  B  82
11-3  B  70
11-5  A  95
11-7  A  90
11-10  A  70
11-11  B  95
11-17  A  150
・    ・  ・
・    ・  ・
・    ・  ・

Book1.csvに以下のようにファイルを更新したいです。

日付  品番 在庫 売り 補充
11-1  A  101  0   0  
11-1  B  82  0   0
11-3  B  70  12  0
11-5  A  95  6   0
11-7  A  90  5   0
11-10  A  70  20 0
11-11  B  95   0 25 
11-17  A  150  0  80 
・    ・  ・
・    ・  ・
・    ・  ・

※売り=在庫(現在)-在庫(一つ前)>0
※補充=在庫(現在)-在庫(一つ前)<0
※品番Aと品番Bは出てくる頻度はばらばらです。

発生している問題・エラーメッセージ

Book1.csvの読み込み、diff関数(差分)、まではうまくいきましたが、
行数が多くてメモリーエラーになります。

該当のソースコード

以下のように書いて100万行あるcsvを処理するとエラーになってしまいます。

diff_ser = df.groupby('品番')['在庫'].diff()
df.loc[diff_ser<0,'売り'] = -diff_ser
df.loc[diff_ser>0,'補充'] = diff_ser
df = df.fillna(0)

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

こちらの質問の質問者と同一の方ですかね?
何故わざわざ名前を変えたのでしょうか?出来れば前の質問にコメントなりのレスポンスをしてから新しい質問を立てていただけたらと思います。

それはさておき
どの箇所でメモリーエラーが起こっているかによりますが、diff() は成功しているとのことですので、

  • '在庫'、'売り'、'補充'列の型を 'int16' または 'uint16' にする

(現状 '売り','補充'の列の型'float64'なので 一列あたりのサイズが 1/4になります。データ範囲が合わない場合は 'int32'としてください )

  • DataFrameのコピーを作らない (例えば、df = df.fillna(0)df.fillna(0, inplace=True)) に置き換える)

あたりで動作するのではないでしょうか

具体的には

Python

1# diff のデータ型を int16 にしておく 2diff_ser = df.groupby('品番')['在庫'].diff().fillna(0).astype('int16') 3# 予め 0 で埋めた列を作成(型は int16 を指定) 4df['売り'] = df['補充'] = pd.Series(0, index=diff_ser.index, dtype='int16') 5df.loc[diff_ser<0,'売り'] = -diff_ser 6df.loc[diff_ser>0,'補充'] = diff_ser

あたりでどうでしょうか

投稿2019/02/06 05:28

magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

osamu55

2019/02/06 13:07

回答ありがとうありがとうございます。質問者は同じです。なぜか前のアカウントでログインできず、返信できておらず申し訳ありませんでした。 今回の教えていただいたプログラムで書きましたが、まだメモリエラーが出てしまいました。 自分でもネットを探してやってみてますが、初心者で分からず、 他には方法がございましたら教えていただけませんでしょうか??
magichan

2019/02/07 00:14

このアプローチでは、回答にも書いたように'在庫'列のデータサイズを予め df['在庫'] = df['在庫'].astype('int16') などと指定して使用サイズを減らしておく。 メモリーエラーが起こる前に import gc gc.collect() を行って、強制的にガベージコレクトを動かす。 くらいしか手段が残ってないと思いますので、もしそれでも駄目だった場合は違うアプローチを取るべきかと思います。 (違うアプローチに関しては、あとで別回等します)
guest

0

ベストアンサー

別回等です。

pandas.read_csv() にてCSVファイルを読み込む際に chunksize パラメータを渡すことでCSVファイルを指定サイズ毎に読み込むことができます。
また、DataFrame.to_csv() にてCSVファイルに書き出す際にはパラメータに mode='a' を渡す事で追記モードにて書き出すことができます。
これらの機能を利用して、CSVファイルを部分毎に「読み込み」→「変換」→「書き出し」を繰り返すといった手法をとると良いのではないでしょうか。

Python

1import pandas as pd 2 3prev_df = None 4 5# データを10000行ごとに読み込む 6for chunked_df in pd.read_csv('data.csv', chunksize=10000): 7 #一つ前のチャンクと結合(差分を求める処理を行う為、前のデータも必要となる) 8 df = pd.concat([prev_df, chunked_df]) 9 10 diff_ser = df.groupby('品番')['在庫'].diff() 11 df.loc[diff_ser<0,'売り'] = -diff_ser 12 df.loc[diff_ser>0,'補充'] = diff_ser 13 df = df.fillna(0) 14 15 # 2重書き込みを避けるために、前のチャンク部を削除 16 df = df.loc[chunked_df.index] 17 18 if prev_df is None: 19 # 最初のチャンクの場合は通常の書き込み 20 df.to_csv('out.csv') 21 else: 22 # 2つ目移行は追記モードで書き込み(その場合はヘッダも書かない) 23 df.to_csv('out.csv', mode='a', header=None) 24 25 prev_df = chunked_df

投稿2019/02/07 00:30

magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

osamu55

2019/02/09 09:08

ありがとうございます。 本日トライしてみて解決いたしました!丁寧にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問