2017-05-28 44 views
1

これはすでに最速のメソッドかどうか、私はこれを非効率的に実行しているかどうかは分かりません。pd.get_dummies()が大規模で遅い

可能なレベルが27k +ある特定のカテゴリの列をホットエンコードする必要があります。

def hot_encode_column_in_both_datasets(column_name,df,df2,sparse=True): 
    col1b = set(df2[column_name].unique()) 
    col1a = set(df[column_name].unique()) 
    combined_cats = list(col1a.union(col1b)) 
    df[column_name] = df[column_name].astype('category', categories=combined_cats) 
    df2[column_name] = df2[column_name].astype('category', categories=combined_cats) 

    df = pd.get_dummies(df, columns=[column_name],sparse=sparse) 
    df2 = pd.get_dummies(df2, columns=[column_name],sparse=sparse) 
    try: 
     del df[column_name] 
     del df2[column_name] 
    except: 
     pass 
    return df,df2 

)(2つの異なるデータセットで異なる値を持っているので、私は最初get_dummiesを使用する前に、レベルを組み合わせた列には、しかし、そのは、2時間以上実行されて、それはまだ熱いエンコーディングを立ち往生しています。

私はここで間違ったことをしていますか?それとも、大規模なデータセットで実行するのは自然なのでしょうか?

Dfには6.8mの行と27の列があり、Df2には19990の行と27の列があります。

アドバイスありがとう、ありがとう! :)

+0

'except:pass'は常に間違っています。代わりに 'if column_name in df:'としたいと思います。残りの質問については、どの特定のラインが長い時間を取っているかを教えてください。 –

+0

@JohnZwinckあなたの入力をありがとうございます:)この場合、私はそれが本当に問題だとは思わない、間違っている場合は私を修正してください。 – Wboy

+0

@JohnZwinck私が言及したように、get_dummies()は長い時間を費やしています – Wboy

答えて

1

私はget_dummies source codeを簡単に見直しました。あなたの使用例では希薄さを十分に活用していない可能性があります。次のアプローチ速くなるかもしれませんが、私はあなたが持っている19Mレコードにすべての方法まで、それを拡大しようとしませんでした。他の回答から

import numpy as np 
import pandas as pd 
import scipy.sparse as ssp 

np.random.seed(1) 
N = 10000 

dfa = pd.DataFrame.from_dict({ 
    'col1': np.random.randint(0, 27000, N) 
    , 'col2b': np.random.choice([1, 2, 3], N) 
    , 'target': np.random.choice([1, 2, 3], N) 
    }) 

# construct an array of the unique values of the column to be encoded 
vals = np.array(dfa.col1.unique()) 
# extract an array of values to be encoded from the dataframe 
col1 = dfa.col1.values 
# construct a sparse matrix of the appropriate size and an appropriate, 
# memory-efficient dtype 
spmtx = ssp.dok_matrix((N, len(vals)), dtype=np.uint8) 
# do the encoding. NB: This is only vectorized in one of the two dimensions. 
# Finding a way to vectorize the second dimension may yield a large speed up 
for idx, val in enumerate(vals): 
    spmtx[np.argwhere(col1 == val), idx] = 1 

# Construct a SparseDataFrame from the sparse matrix and apply the index 
# from the original dataframe and column names. 
dfnew = pd.SparseDataFrame(spmtx, index=dfa.index, 
          columns=['col1_' + str(el) for el in vals]) 
dfnew.fillna(0, inplace=True) 

UPDATE

借入洞察herehere私は両方の次元で解をベクトル化できました。私の限られたテストでは、SparseDataFrameの構築が実行時間を数倍に伸ばしているようだと指摘しました。したがって、DataFrameのようなオブジェクトを返す必要がなければ、多くの時間を節約できます。このソリューションは、2 + DataFramesを同じ数の列を持つ2-d配列にエンコードする必要がある場合も処理します。

import numpy as np 
import pandas as pd 
import scipy.sparse as ssp 

np.random.seed(1) 
N1 = 10000 
N2 = 100000 

dfa = pd.DataFrame.from_dict({ 
    'col1': np.random.randint(0, 27000, N1) 
    , 'col2a': np.random.choice([1, 2, 3], N1) 
    , 'target': np.random.choice([1, 2, 3], N1) 
    }) 

dfb = pd.DataFrame.from_dict({ 
    'col1': np.random.randint(0, 27000, N2) 
    , 'col2b': np.random.choice(['foo', 'bar', 'baz'], N2) 
    , 'target': np.random.choice([1, 2, 3], N2) 
    }) 

# construct an array of the unique values of the column to be encoded 
# taking the union of the values from both dataframes. 
valsa = set(dfa.col1.unique()) 
valsb = set(dfb.col1.unique()) 
vals = np.array(list(valsa.union(valsb)), dtype=np.uint16) 


def sparse_ohe(df, col, vals): 
    """One-hot encoder using a sparse ndarray.""" 
    colaray = df[col].values 
    # construct a sparse matrix of the appropriate size and an appropriate, 
    # memory-efficient dtype 
    spmtx = ssp.dok_matrix((df.shape[0], vals.shape[0]), dtype=np.uint8) 
    # do the encoding 
    spmtx[np.where(colaray.reshape(-1, 1) == vals.reshape(1, -1))] = 1 

    # Construct a SparseDataFrame from the sparse matrix 
    dfnew = pd.SparseDataFrame(spmtx, dtype=np.uint8, index=df.index, 
           columns=[col + '_' + str(el) for el in vals]) 
    dfnew.fillna(0, inplace=True) 
    return dfnew 

dfanew = sparse_ohe(dfa, 'col1', vals) 
dfbnew = sparse_ohe(dfb, 'col1', vals) 
+0

ねえ、あなたの答えに感謝! :)これは第2のデータフレームのカテゴリの会計処理にもどのように対処しますか? – Wboy

+0

こんにちは! :)私はこれを正しく理解している場合、これは元のデータフレームの右に結合するのではなく、疎なデータフレームとして現在の列を返します。また、ValueErrorを取得しました。現在のfill_value nanをuint8 dtypeに強制することができません。 – Wboy

+0

ええと、ValueErrorを再現できません。私は最近リリースされたパンダ0.20.1を使用しています。オリジナルの列をすべて含む完全なデータフレームを再構成する必要がある場合は、最後にこのステートメントを追加することができます。 'dfa = pd.concat([dfanew、dfa.drop( 'col1'、axis = 1)]、axis = 1) '。 – blueogive

関連する問題