2016-06-26 11 views
7

大きなデータフレームがあります。これはテストセットとモデル構築用のトレインセットに分割したいと思います。ただし、メモリの上限に達しているため、DataFrameを複製したくありません。最小のメモリフットプリントで大きなパンダのデータフレームを分割する

操作がポップに似ていますが、同時にデータフレームの部分を削除し、私は新しいデータフレームに割り当てることができます大規模なセグメントのため、ありますか?このような何か:

# Assume I have initialized a DataFrame (called "all") which contains my large dataset, 
# with a boolean column called "test" which indicates whether a record should be used for 
# testing. 
print len(all) 
# 10000000 
test = all.pop_large_segment(all[test]) # not a real command, just a place holder 
print len(all) 
# 8000000 
print len(test)  
# 2000000 
+3

私が知っている限り、あなたが割り当てを行う瞬間、パンダはコピーを作成します。電車とテストの指標を保存するだけであれば効果がありますか? – ayhan

+0

質問に答えるのではなく、おそらく他の関連するアイデア: - 読み込み時にデータセットを分割することはできませんか? - あるいは 'dask'(http://dask.pydata.org/en/latest/)のようなものを使用しますか? –

+0

私が知っている唯一の理由は、HDF5テーブルからHDF5テーブルを別々にロードし、ロード時にスプリットを行うことです。つまり、トレーニングとして最初にいくつかの行をロードし、残りの部分をスプリットとして適切な答えを出すことができます。 – RexFuzzle

答えて

3

使用すると、1つの以上の列を追加するためのスペースを持っている場合、あなたは、あなたのテストのためにフィルタリングすることができ、ランダムな値を持つものを追加することができます。ここでは、0と1の間のユニフォームを使用しましたが、別の割合を使用したい場合は何でも使用できます。

df = pd.DataFrame({'one':[1,2,3,4,5,4,3,2,1], 'two':[6,7,8,9,10,9,8,7,6], 'three':[11,12,13,14,15,14,13,12,11]}) 
df['split'] = np.random.randint(0, 2, size=len(df)) 

もちろん、完全に新しい列を追加するスペースが必要です。特に、データが非常に長い場合は、そうでないかもしれません。あなたのデータはcsv形式にあった、あなたが行数を知っていた場合

別のオプションは、例えば、働くだろう。 randomintと上記と同様んが、パンダread_csv()skiprows引数にそのリストを渡します。

num_rows = 100000 
all = range(num_rows) 

some = np.random.choice(all, replace=False, size=num_rows/2) 
some.sort() 
trainer_df = pd.read_csv(path, skiprows=some) 

rest = [i for i in all if i not in some] 
rest.sort() 
df = pd.read_csv(path, skiprows=rest) 

それは特にリスト内包のループで、アップフロント少し不格好だし、メモリ内のこれらのリストを作成します残念なことですが、データ全体の半分のコピーを作成するだけでなく、メモリ全体の方が優れているはずです。あなたがモデルを適用し、その後、その後、残りのデータとトレーニングデータフレームを上書きし、モデルをトレーニング、トレーナーのサブセットをロードすることができ、それはさらに多くのメモリ使いやすくするために

。あなたはsomerestを持ち歩いて立ち往生しますが、データの両方を同時に読み込む必要はありません。

1

@ jeff-lと同様の処理を行います。つまり、データフレームをファイルに保存します。 csvとして読み込んだ場合は、chunksizeキーワードを使用してください。次のスクリプトは、この説明:

import pandas 
import numpy 

test = 5 
m, n = 2*test, 3 

df = pandas.DataFrame(
    data=numpy.random.random((m, n)) 
) 

df['test'] = [0] * test + [1] * test 

df.to_csv('tmp.csv', index=False) 

for chunk in pandas.read_csv('tmp.csv', chunksize=test): 
    print chunk 
    del chunk 
+0

これは、ディスクからデータを順番に取り出します。トレーニングデータセットは偏りのないサンプルでなければなりません。これは、データがすでにディスク上でランダムにシャッフルされていることを知っていればうまくいくでしょう。 – Jeff

1

を他の回答には、ファイルの読み込みにより集中しているように、私はあなたのデータフレームがファイルから読み込まれていない何らかの理由であれば、あなたも、何かを行うことができますね。

たぶん、あなたはDataFrame.drop methodのコードを見て、あなたのデータフレームインプレースを変更するためにそれを修正する(これdrop方法が既に行う)他のRAWが返さ取得することができます。

class DF(pd.DataFrame): 
    def drop(self, labels, axis=0, level=None, inplace=False, errors='raise'): 
     axis = self._get_axis_number(axis) 
     axis_name = self._get_axis_name(axis) 
     axis, axis_ = self._get_axis(axis), axis 

     if axis.is_unique: 
      if level is not None: 
       if not isinstance(axis, pd.MultiIndex): 
        raise AssertionError('axis must be a MultiIndex') 
       new_axis = axis.drop(labels, level=level, errors=errors) 
      else: 
       new_axis = axis.drop(labels, errors=errors) 
      dropped = self.reindex(**{axis_name: new_axis}) 
      try: 
       dropped.axes[axis_].set_names(axis.names, inplace=True) 
      except AttributeError: 
       pass 
      result = dropped 

     else: 
      labels = com._index_labels_to_array(labels) 
      if level is not None: 
       if not isinstance(axis, MultiIndex): 
        raise AssertionError('axis must be a MultiIndex') 
       indexer = ~axis.get_level_values(level).isin(labels) 
      else: 
       indexer = ~axis.isin(labels) 

      slicer = [slice(None)] * self.ndim 
      slicer[self._get_axis_number(axis_name)] = indexer 

      result = self.ix[tuple(slicer)] 

     if inplace: 
      dropped = self.ix[labels] 
      self._update_inplace(result) 
      return dropped 
     else: 
      return result, self.ix[labels] 

df = DF({'one':[1,2,3,4,5,4,3,2,1], 'two':[6,7,8,9,10,9,8,7,6], 'three':[11,12,13,14,15,14,13,12,11]}) 

dropped = df.drop(range(5), inplace=True) 
# or : 
# partA, partB = df.drop(range(5)) 

この例では、おそらく実際にメモリ効率的ではありませんが、多分あなたはオブジェクト指向solutiのいくつかの種類を使用することによって、より良い何かを把握することができます。このように動作しますどのこのように

+0

私はこの操作を実行している間に余分なスペースが必要だと思いますが、小さなチャンクで繰り返し使用できます。ファイルから読み込むよりも速いかもしれません。 – ayhan

+0

これは興味深いアプローチです。再び、データを順番に分割しています。 'partA'と' partB'の結果では、一方のデータの上半分ともう一方のデータの下半分になります。データがディスク上でランダムにシャッフルされない限り、バイアスされたサンプル。 – Jeff

+0

@JeffL。私は実際には、random関数(random.sample(range(len(df))など)の引数として機能の数よりも小さいランダムな一意の整数のリストを使用することで、ここでは 'range(5)'と同じように値の連続範囲の代わりに) 'n_wanted_values') – mgc

関連する問題