Разделение списков столбцов в Pandas DataFrame

Я ищу хороший способ решить следующую проблему. Мое текущее исправление не особенно чистое, и я надеюсь извлечь уроки из вашего понимания.

Предположим, у меня есть Panda DataFrame, записи которого выглядят так:

>>> df=pd.DataFrame(index=[1,2,3],columns=['Color','Texture','IsGlass'])

>>> df['Color']=[np.nan,['Red','Blue'],['Blue', 'Green', 'Purple']]
>>> df['Texture']=[['Rough'],np.nan,['Silky', 'Shiny', 'Fuzzy']]
>>> df['IsGlass']=[1,0,1]

>>> df
                            Color                   Texture   IsGlass
    1                         NaN                  ['Rough']        1
    2              ['Red', 'Blue']                       NaN        0 
    3  ['Blue', 'Green', 'Purple']  ['Silky','Shiny','Fuzzy']       1

Таким образом, каждое наблюдение в индексе соответствует чему-то, что я измерил в отношении его цвета, текстуры и того, стекло это или нет. Что я хотел бы сделать, так это превратить это в новый «индикатор» DataFrame, создав столбец для каждого наблюдаемого значения и изменив соответствующую запись на единицу, если я ее наблюдал, и NaN, если у меня нет информации.

>>> df
         Red Blue Green Purple Rough Silky Shiny Fuzzy Is Glass               
    1    Nan  Nan  Nan   Nan    1     NaN   Nan   Nan     1        
    2     1    1   Nan   Nan    Nan   Nan   Nan   Nan     0 
    3    Nan   1    1     1     Nan    1     1     1      1

У меня есть решение, которое перебирает каждый столбец, просматривает его значения и через серию Try/Excepts для значений, отличных от Nan, разбивает списки, создает новый столбец и т. д. и объединяет.

Это мой первый пост в StackOverflow — надеюсь, этот пост соответствует правилам публикации. Спасибо.


person Adam Azzam    schedule 25.10.2017    source источник
comment
Формат ваших данных - строка или список? ['Синий, зеленый, фиолетовый']? или ['Синий', 'Зеленый', 'Фиолетовый']   -  person BENY    schedule 26.10.2017
comment
Спасибо. Это ['Синий','Зеленый','Фиолетовый']. Я отредактирую соответственно.   -  person Adam Azzam    schedule 26.10.2017
comment
Добавьте мое решение ~ :-)   -  person BENY    schedule 26.10.2017


Ответы (3)


Укладка хаков!

from sklearn.preprocessing import MultiLabelBinarizer

mlb = MultiLabelBinarizer()

df = df.stack().unstack(fill_value=[])

def b(c):
    d = mlb.fit_transform(c)
    return pd.DataFrame(d, c.index, mlb.classes_)

pd.concat([b(df[c]) for c in ['Color', 'Texture']], axis=1).join(df.IsGlass)

   Blue  Green  Purple  Red  Fuzzy  Rough  Shiny  Silky IsGlass
1     0      0       0    0      0      1      0      0       1
2     1      0       0    1      0      0      0      0       0
3     1      1       1    0      1      0      1      1       1
person piRSquared    schedule 25.10.2017
comment
Мы используем MultiLabelBinarizer из-за скорости? - person BENY; 26.10.2017
comment
@Вен первое что пришло в голову и нет времени предлагать варианты - person piRSquared; 26.10.2017
comment
Понял :-) ЛОЛ! - person BENY; 26.10.2017
comment
Я принимаю ваш ответ, потому что я узнал от него больше всего. Другие ответы великолепны, и то, о чем я просил, но ваш ответ позволяет мне легко просмотреть список ключей. В реальной проблеме, над которой я работаю, в моих столбцах есть записи, которые являются строками, когда сделано одно наблюдение, и списком строк, когда сделано два или более. Столбец может выглядеть как ['Красный',['Красный,'Синий'],'Зеленый']. В этом случае MLB не очень подходит для решения этой проблемы, но мне удалось обойти это. Если у вас есть дополнительные сведения о других инструментах предварительной обработки, которые могли бы справиться с этим, сообщите мне об этом. Спасибо! - person Adam Azzam; 26.10.2017

Я просто использую pandas, get_dummies

l=[pd.get_dummies(df[x].apply(pd.Series).stack(dropna=False)).sum(level=0) for x in ['Color','Texture']]
pd.concat(l,axis=1).assign(IsGlass=df.IsGlass)
Out[662]: 
   Blue  Green  Purple  Red  Fuzzy  Rough  Shiny  Silky  IsGlass
1     0      0       0    0      0      1      0      0        1
2     1      0       0    1      0      0      0      0        0
3     1      1       1    0      1      0      1      1        1
person BENY    schedule 26.10.2017
comment
@AdamAzzam Yw~ Спокойной ночи - person BENY; 26.10.2017

Для каждой текстуры/цвета в каждой строке я проверяю, равно ли значение null. Если нет, мы добавляем это значение как столбец = 1 для этой строки.

import numpy as np
import pandas as pd

df=pd.DataFrame(index=[1,2,3],columns=['Color','Texture','IsGlass'])

df['Color']=[np.nan,['Red','Blue'],['Blue', 'Green', 'Purple']]
df['Texture']=[['Rough'],np.nan,['Silky', 'Shiny', 'Fuzzy']]
df['IsGlass']=[1,0,1]

for row in df.itertuples():

    if not np.all(pd.isnull(row.Color)):
        for val in row.Color:
            df.loc[row.Index,val] = 1     

    if not np.all(pd.isnull(row.Texture)):
        for val in row.Texture:
            df.loc[row.Index,val] = 1
person Nathan H    schedule 25.10.2017