Скажем, у нас есть этот DF:

df = pd.DataFrame({
        'string': ['blue',
                   'blue,red',
                   'red',
                   'purple',
                   'blue,red,green,yellow,magenta,purple',
                   '',
                   'yellow,purple']})

Скажем, мы хотим разделить эти строки на каждую запятую и поместить их в новые столбцы. Как показано здесь (Как разделить текст на несколько значений в файле CSV с помощью Python?) и здесь (Разделить один столбец на несколько столбцов с помощью нескольких разделителей в Pandas), мы можем использовать str.split так:

df[['blue', 'red', 'green', 'yellow', 'magenta', 'purple']] = df['string'].str.split(',',expand=True)
df

Результат:

    string                                  blue    red     green   yellow  magenta purple

0   blue                                    blue    None    None    None    None    None
1   blue,red                                blue    red     None    None    None    None
2   red                                     red     None    None    None    None    None
3   purple                                  purple  None    None    None    None    None
4   blue,red,green,yellow,magenta,purple    blue    red     green   yellow  magenta purple
5                                                   None    None    None    None    None
6   yellow,purple                           yellow  purple  None    None    None    None

Индексы 0, 1 и 4 работают так, как я хочу, с правильной категоризацией цветов в новых столбцах.

По другим индексам цвета классифицируются неверно. Обратите внимание, что приведенные выше примеры не решают мою проблему, поскольку в них нет недостающих точек / уровней данных. Как это исправить? (А также добавьте «Нет» для индекса 5, столбец «синий»?)

Большое спасибо

1
johnjohn 22 Ноя 2021 в 13:22

3 ответа

Лучший ответ

Я бы сделал это следующим образом

import pandas as pd
df = pd.DataFrame({
        'string': ['blue',
                   'blue,red',
                   'red',
                   'purple',
                   'blue,red,green,yellow,magenta,purple',
                   '',
                   'yellow,purple']})
def convert_to_dict(string):
    return dict((i,i) for i in string.split(",") if i)
df2 = df['string'].apply(convert_to_dict).apply(pd.Series)
finaldf = pd.concat([df,df2],axis=1)
print(finaldf)

Выход

                                 string  blue  red  purple  green  yellow  magenta
0                                  blue  blue  NaN     NaN    NaN     NaN      NaN
1                              blue,red  blue  red     NaN    NaN     NaN      NaN
2                                   red   NaN  red     NaN    NaN     NaN      NaN
3                                purple   NaN  NaN  purple    NaN     NaN      NaN
4  blue,red,green,yellow,magenta,purple  blue  red  purple  green  yellow  magenta
5                                         NaN  NaN     NaN    NaN     NaN      NaN
6                         yellow,purple   NaN  NaN  purple    NaN  yellow      NaN

Объяснение: Важной частью является преобразование строки в dict, поэтому для каждой пары "ключ-значение" имеется одинаковое значение. Затем я конвертирую (одиночные pandas.Series удерживающие dict s) в pandas.DataFrame и pandas.concat его с исходным pandas.DataFrame.

1
Daweo 22 Ноя 2021 в 13:31
Большое спасибо, @Daweo. +1 за это прекрасное альтернативное решение с использованием словаря.
 – 
johnjohn
22 Ноя 2021 в 14:05
import pandas as pd
from typing import List
from pandas import DataFrame    


# your input
df = pd.DataFrame({
        'string': ['blue',
                   'blue,red',
                   'red',
                   'purple',
                   'blue,red,green,yellow,magenta,purple',
                   '',
                   'yellow,purple']})


# define columns
input_col = "string"    
encoded_col = "string_enriched"

# unique colors
unique_colors: List[str] = sorted([x for x in set(sum([x.split(",") for x in df[input_col].tolist()], [])) if x])

# create column with unique colors encoded
df[encoded_col] = df[input_col].apply(lambda x: (1 if w in x.split(",") else 0 for w in unique_colors))

# enrich encoded column swapping 0,1 to colors
df[encoded_col] = df.apply(lambda row: (w[1] if w[0] else "" for w in zip(row[encoded_col], unique_colors)), axis=1)

# explode column into multiple columns
dx = pd.DataFrame(df[encoded_col].to_list(), columns = unique_colors)

# concat two dataframes horizontaly
df_out: DataFrame = pd.concat([df[input_col], dx], axis=1)
1
Dariusz Krynicki 22 Ноя 2021 в 14:06
1
Большое спасибо за альтернативное решение! +1
 – 
johnjohn
22 Ноя 2021 в 14:04