2016-09-13 4 views
5

整数にカテゴリ変数を再コーディングLabelEncoderスピードアップする方法:私はこのフォームで行ごとに2つの文字列を持つ大規模なCSVファイルを持っている

g,k 
a,h 
c,i 
j,e 
d,i 
i,h 
b,b 
d,d 
i,a 
d,h 

は、私が最初の2列に読み込み、次のように整数に文字列を再コーディング:

import pandas as pd 
df = pd.read_csv("test.csv", usecols=[0,1], prefix="ID_", header=None) 
from sklearn.preprocessing import LabelEncoder 

# Initialize the LabelEncoder. 
le = LabelEncoder() 
le.fit(df.values.flat) 

# Convert to digits. 
df = df.apply(le.transform) 

このコードはhttps://stackoverflow.com/a/39419342/2179021です。

コードは非常にうまく動作しますが、dfが大きい場合は遅くなります。私は各ステップをタイムリーに行い、その結果は私にとって驚くべきものでした。

  • pd.read_csvが約40秒かかる。
  • le.fit(df.values.flat)は約30秒である。
  • df = df.apply(le.transform)は約250秒かかる。

この最後のステップをスピードアップする方法はありますか?それは彼らのすべての最速のステップでなければならないように感じる!


maxymooによってRAM 4GBの

以下の答えを持つコンピュータ上で再コード化ステップのためのより多くのタイミングが速いですが、正しい答えを与えるものではありません。

0 1 
0 4 6 
1 0 4 
2 2 5 
3 6 3 
4 3 5 
5 5 4 
6 1 1 
7 3 2 
8 5 0 
9 3 4 

「D」は第二に、最初の列における3が、2にマッピングされていることに注意してください。問題の上から例CSVを取って、それはそれを翻訳します。

私はhttps://stackoverflow.com/a/39356398/2179021から解決策を試して、以下を取得しました。

df = pd.DataFrame({'ID_0':np.random.randint(0,1000,1000000), 'ID_1':np.random.randint(0,1000,1000000)}).astype(str) 
df.info() 
memory usage: 7.6MB 
%timeit x = (df.stack().astype('category').cat.rename_categories(np.arange(len(df.stack().unique()))).unstack()) 
1 loops, best of 3: 1.7 s per loop 

は、その後、私は10

df = pd.DataFrame({'ID_0':np.random.randint(0,1000,10000000), 'ID_1':np.random.randint(0,1000,10000000)}).astype(str) 
df.info() 
memory usage: 76.3+ MB 
%timeit x = (df.stack().astype('category').cat.rename_categories(np.arange(len(df.stack().unique()))).unstack()) 
MemoryError        Traceback (most recent call last) 

の要因によりデータフレームのサイズを増加し、この方法は、それがクラッシュし、この比較的小さなデータフレームを翻訳しようとしているので、多くのRAMを使用するように表示されます。

また、10万行の大きなデータセットでLabelEncoderをタイムリーにしました。それはクラッシュすることなく実行されますが、フィットラインだけでも50秒かかりました。 df.apply(le.transform)のステップには約80秒かかりました。

はどうすればよい:

  1. はmaxymooの答えのおおよその速度とLabelEncoderのおおよそのメモリ使用量の何かを取得しますが、データフレームは、2つの列を持つ場合、それは正しい答えを与えます。
  2. (LabelEncoderで可能なように)別のデータに再利用できるようにマッピングを保存しますか?
+0

あなたのCSVどのくらいです - 行と列は?いくつのファイルがありますか? – wwii

+0

@wwii約10百万行と百万個のle.classes。 – eleanora

+0

'' 'groupby ....' 'は何を達成するのですか? – wwii

答えて

4

pandas categoryデータ型を使用する方がはるかに高速なようです。ここあなたが使用できることを(おそらく公式の学習scikitでこれを見ないであろうことを、カスタムトランスクラスです:

In [87]: df = pd.DataFrame({'ID_0':np.random.randint(0,1000,1000000), 
          'ID_1':np.random.randint(0,1000,1000000)}).astype(str) 

In [88]: le.fit(df.values.flat) 
     %time x = df.apply(le.transform) 
CPU times: user 6.28 s, sys: 48.9 ms, total: 6.33 s 
Wall time: 6.37 s 

In [89]: %time x = df.apply(lambda x: x.astype('category').cat.codes) 
CPU times: user 301 ms, sys: 28.6 ms, total: 330 ms 
Wall time: 331 ms 

EDITを:内部的にこれはLabelEncoderがソートされた検索を使用してではなく、一方、ハッシュテーブルを使用していますメンテナは依存関係としてパンダを持っている必要はありませんので、リリース)

import pandas as pd 
from pandas.core.nanops import unique1d 
from sklearn.base import BaseEstimator, TransformerMixin 

class PandasLabelEncoder(BaseEstimator, TransformerMixin): 
    def fit(self, y): 
     self.classes_ = unique1d(y) 
     return self 

    def transform(self, y): 
     s = pd.Series(y).astype('category', categories=self.classes_) 
     return s.cat.codes 
+0

ありがとうございます。私は2つの列にわたって一貫性のあるエンコーディングが必要ですが、私は両方の列にすべての値が表示されるわけではありません。 – eleanora

+0

このマッピングを別のデータフレームに適用できる必要があります。 labelencoderはそれを保存する方法はありますか? – eleanora

+0

ありがとうございました!それは非常に興味深いです、 – eleanora

3

私はデータフレームでこれを試してみました:

In [xxx]: import string 
In [xxx]: letters = np.array([c for c in string.ascii_lowercase]) 
In [249]: df = pd.DataFrame({'ID_0': np.random.choice(letters, 10000000), 'ID_1':np.random.choice(letters, 10000000)}) 

これは次のようになります。

In [261]: df.head() 
Out[261]: 
    ID_0 ID_1 
0 v z 
1 i i 
2 d n 
3 z r 
4 x x 

In [262]: df.shape 
Out[262]: (10000000, 2) 

したがって、1,000万行です。局所的には、私のタイミングは以下のとおりです。

In [257]: % timeit le.fit(df.values.flat) 
1 loops, best of 3: 17.2 s per loop 

In [258]: % timeit df2 = df.apply(le.transform) 
1 loops, best of 3: 30.2 s per loop 

それから私は数字にdictのマッピング文字を作り、pandas.Series.mapを使用:

In [248]: letters = np.array([l for l in string.ascii_lowercase]) 
In [263]: d = dict(zip(letters, range(26))) 

In [273]: %timeit for c in df.columns: df[c] = df[c].map(d) 
1 loops, best of 3: 1.12 s per loop 

In [274]: df.head() 
Out[274]: 
    ID_0 ID_1 
0 21 25 
1  8  8 
2  3 13 
3 25 17 
4 23 23 

だから、選択肢かもしれません。ディクテーションは、データ内に発生するすべての値を持つだけです。

EDIT:OPは、カテゴリを使用して、その2番目のオプションのタイミングを質問しました。これは私が得るものです:

In [40]: %timeit x=df.stack().astype('category').cat.rename_categories(np.arange(len(df.stack().unique()))).unstack() 
1 loops, best of 3: 13.5 s per loop 

EDIT:第二のコメントにつき:

In [45]: %timeit uniques = np.sort(pd.unique(df.values.ravel())) 
1 loops, best of 3: 933 ms per loop 

In [46]: %timeit dfc = df.apply(lambda x: x.astype('category', categories=uniques)) 
1 loops, best of 3: 1.35 s per loop 
+0

これは素晴らしい答えです、私はあなたがそのような辞書、非常に素晴らしいトリックをマップすることができたか分からなかった。 btwより機能的な構文は 'df.apply(lambda c:c.map(d))'となります(これは何らかの理由で0.5秒遅くなります) – maxymoo

+0

ありがとうございます。 'uniques = np.sort(pd.unique(df.values.ravel())) df.apply(ラムダx:x。astype( 'category'、categories =ユニーク)) 'too please? – eleanora

+0

タイミングを取っていただきありがとうございます。実行したコードを意味するものではありませんでした。私はコメントに貼り付けた2行を文字通り意味していました。あなたは他に何か必要はないはずです(例えば積み重ねたり積み上げたりするなど)? – eleanora

関連する問題