2017-07-25 6 views
12

मैं कई स्तंभों में तत्वों की एक सूची से युक्त एक पांडा स्तंभ को तोड़ना चाहता हूं क्योंकि अद्वितीय तत्व हैं जैसे one-hot-encode उन्हें (1 मूल्य के साथ एक पंक्ति में मौजूद किसी दिए गए तत्व का प्रतिनिधित्व करते हुए और 0 अनुपस्थिति के मामले में)।एक सूची वाले पांडा कॉलम से एक-हॉट-एन्कोड कैसे करें?

df

Col1 Col2 Apple Orange Banana Grape 
C  33  1  1  1  0 
A  2.5 1  0  0  1 
B  42  0  0  1  0 

मैं पांडा उपयोग कर सकते हैं कैसे/sklearn प्राप्त करने के लिए:

उदाहरण के लिए, dataframe लेने df

Col1 Col2   Col3 
C  33  [Apple, Orange, Banana] 
A  2.5 [Apple, Grape] 
B  42  [Banana] 

मैं में बदलने के लिए चाहते हैं इस?

उत्तर

15

हम भी sklearn.preprocessing.MultiLabelBinarizer उपयोग कर सकते हैं:

from sklearn.preprocessing import MultiLabelBinarizer 

mlb = MultiLabelBinarizer() 
df = df.join(pd.DataFrame(mlb.fit_transform(df.pop('Col3')), 
          columns=mlb.classes_, 
          index=df.index)) 

परिणाम:

In [77]: df 
Out[77]: 
    Col1 Col2 Apple Banana Grape Orange 
0 C 33.0  1  1  0  1 
1 A 2.5  1  0  1  0 
2 B 42.0  0  1  0  0 
+1

आपको समय दिलचस्प लगेगा। – piRSquared

6

उपयोग get_dummies:

df_out = df.assign(**pd.get_dummies(df.Col3.apply(lambda x:pd.Series(x)).stack().reset_index(level=1,drop=True)).sum(level=0)) 

आउटपुट:

Col1 Col2      Col3 Apple Banana Grape Orange 
0 C 33.0 [Apple, Orange, Banana]  1  1  0  1 
1 A 2.5   [Apple, Grape]  1  0  1  0 
2 B 42.0     [Banana]  0  1  0  0 

सफाई स्तंभ:

df_out.drop('Col3',axis=1) 

आउटपुट:

Col1 Col2 Apple Banana Grape Orange 
0 C 33.0  1  1  0  1 
1 A 2.5  1  0  1  0 
2 B 42.0  0  1  0  0 
+1

'get_dummies' साथ' '** के उपयोग के लिए +1, लेकिन इस' .stack() 'और विधि श्रृंखलन की वजह से बड़े dataframes के लिए धीमी गति से हो सकता है। –

+0

@BradSolomon धन्यवाद। –

+0

मुझे यकीन नहीं है कि यह काफी काम करता है ... इसके बाद आज़माएं: 'df = pd.concat ([df, df])' – Alexander

5

आप कर सकते हैं apply साथ Col3 के माध्यम से लूप और सूचकांक जो परिणाम डेटा फ्रेम में हेडर बन के रूप में सूची के साथ एक श्रृंखला में प्रत्येक तत्व को परिवर्तित:

pd.concat([ 
     df.drop("Col3", 1), 
     df.Col3.apply(lambda x: pd.Series(1, x)).fillna(0) 
    ], axis=1) 

#Col1 Col2 Apple Banana Grape Orange 
#0 C 33.0  1.0  1.0 0.0  1.0 
#1 A 2.5  1.0  0.0 1.0  0.0 
#2 B 42.0  0.0  1.0 0.0  0.0 
5

आप Col3 में सभी अद्वितीय फल सेट का उपयोग कर सकते हैं समझ इस प्रकार है:

set(fruit for fruits in df.Col3 for fruit in fruits) 

एक शब्दकोश समझ का उपयोग करना, आप तो प्रत्येक अद्वितीय फल के माध्यम से जाने के लिए और अगर यह कॉलम में है देख सकते हैं।

>>> df[['Col1', 'Col2']].assign(**{fruit: [1 if fruit in cell else 0 for cell in df.Col3] 
            for fruit in set(fruit for fruits in df.Col3 
                for fruit in fruits)}) 
    Col1 Col2 Apple Banana Grape Orange 
0 C 33.0  1  1  0  1 
1 A 2.5  1  0  1  0 
2 B 42.0  0  1  0  0 

समय

dfs = pd.concat([df] * 1000) # Use 3,000 rows in the dataframe. 

# Solution 1 by @Alexander (me) 
%%timeit -n 1000 
dfs[['Col1', 'Col2']].assign(**{fruit: [1 if fruit in cell else 0 for cell in dfs.Col3] 
           for fruit in set(fruit for fruits in dfs.Col3 for fruit in fruits)}) 
# 10 loops, best of 3: 4.57 ms per loop 

# Solution 2 by @Psidom 
%%timeit -n 1000 
pd.concat([ 
     dfs.drop("Col3", 1), 
     dfs.Col3.apply(lambda x: pd.Series(1, x)).fillna(0) 
    ], axis=1) 
# 10 loops, best of 3: 748 ms per loop 

# Solution 3 by @MaxU 
from sklearn.preprocessing import MultiLabelBinarizer 
mlb = MultiLabelBinarizer() 

%%timeit -n 10 
dfs.join(pd.DataFrame(mlb.fit_transform(dfs.Col3), 
          columns=mlb.classes_, 
          index=dfs.index)) 
# 10 loops, best of 3: 283 ms per loop 

# Solution 4 by @ScottBoston 
%%timeit -n 10 
df_out = dfs.assign(**pd.get_dummies(dfs.Col3.apply(lambda x:pd.Series(x)).stack().reset_index(level=1,drop=True)).sum(level=0)) 
# 10 loops, best of 3: 512 ms per loop 

But... 
>>> print(df_out.head()) 
    Col1 Col2      Col3 Apple Banana Grape Orange 
0 C 33.0 [Apple, Orange, Banana] 1000 1000  0 1000 
1 A 2.5   [Apple, Grape] 1000  0 1000  0 
2 B 42.0     [Banana]  0 1000  0  0 
0 C 33.0 [Apple, Orange, Banana] 1000 1000  0 1000 
1 A 2.5   [Apple, Grape] 1000  0 1000  0 
10

विकल्प 1
लघु उत्तर
pir_slow

df.drop('Col3', 1).join(df.Col3.str.join('|').str.get_dummies()) 

    Col1 Col2 Apple Banana Grape Orange 
0 C 33.0  1  1  0  1 
1 A 2.5  1  0  1  0 
2 B 42.0  0  1  0  0 

विकल्प 2
फास्ट उत्तर
pir_fast

v = df.Col3.values 
l = [len(x) for x in v.tolist()] 
f, u = pd.factorize(np.concatenate(v)) 
n, m = len(v), u.size 
i = np.arange(n).repeat(l) 

dummies = pd.DataFrame(
    np.bincount(i * m + f, minlength=n * m).reshape(n, m), 
    df.index, u 
) 

df.drop('Col3', 1).join(dummies) 

    Col1 Col2 Apple Orange Banana Grape 
0 C 33.0  1  1  1  0 
1 A 2.5  1  0  0  1 
2 B 42.0  0  0  1  0 

विकल्प 3
pir_alt1

df.drop('Col3', 1).join(
    pd.get_dummies(
     pd.DataFrame(df.Col3.tolist()).stack() 
    ).astype(int).sum(level=0) 
) 

    Col1 Col2 Apple Orange Banana Grape 
0 C 33.0  1  1  1  0 
1 A 2.5  1  0  0  1 
2 B 42.0  0  0  1  0 

समय परिणाम
कोड

नीचे


def maxu(df): 
    mlb = MultiLabelBinarizer() 
    d = pd.DataFrame(
     mlb.fit_transform(df.Col3.values) 
     , df.index, mlb.classes_ 
    ) 
    return df.drop('Col3', 1).join(d) 


def bos(df): 
    return df.drop('Col3', 1).assign(**pd.get_dummies(df.Col3.apply(lambda x:pd.Series(x)).stack().reset_index(level=1,drop=True)).sum(level=0)) 

def psi(df): 
    return pd.concat([ 
     df.drop("Col3", 1), 
     df.Col3.apply(lambda x: pd.Series(1, x)).fillna(0) 
    ], axis=1) 

def alex(df): 
    return df[['Col1', 'Col2']].assign(**{fruit: [1 if fruit in cell else 0 for cell in df.Col3] 
             for fruit in set(fruit for fruits in df.Col3 
                 for fruit in fruits)}) 

def pir_slow(df): 
    return df.drop('Col3', 1).join(df.Col3.str.join('|').str.get_dummies()) 

def pir_alt1(df): 
    return df.drop('Col3', 1).join(pd.get_dummies(pd.DataFrame(df.Col3.tolist()).stack()).astype(int).sum(level=0)) 

def pir_fast(df): 
    v = df.Col3.values 
    l = [len(x) for x in v.tolist()] 
    f, u = pd.factorize(np.concatenate(v)) 
    n, m = len(v), u.size 
    i = np.arange(n).repeat(l) 

    dummies = pd.DataFrame(
     np.bincount(i * m + f, minlength=n * m).reshape(n, m), 
     df.index, u 
    ) 

    return df.drop('Col3', 1).join(dummies) 

results = pd.DataFrame(
    index=(1, 3, 10, 30, 100, 300, 1000, 3000), 
    columns='maxu bos psi alex pir_slow pir_fast pir_alt1'.split() 
) 

for i in results.index: 
    d = pd.concat([df] * i, ignore_index=True) 
    for j in results.columns: 
     stmt = '{}(d)'.format(j) 
     setp = 'from __main__ import d, {}'.format(j) 
     results.set_value(i, j, timeit(stmt, setp, number=10)) 
+1

यह शानदार है, वास्तव में! पीएस मैंने अभी अपने आखिरी वोटिंग शॉट का इस्तेमाल आज के लिए किया ;-) – MaxU

+0

@MaxU धन्यवाद (-: – piRSquared

+0

यह तेज़ है! अपने समय चार्ट की तरह। मुझे लगता है कि * एक्स-अक्ष * डेटाफ्रेम में पंक्तियों की संख्या है? – Alexander

संबंधित मुद्दे