Горячее кодирование, элементы списка доступа

У меня есть файл.csv, с данными которого я хочу преобразовать некоторые столбцы в один горячий. Проблема возникает во второй последней строке, где горячий индекс (например, первая функция) помещается во все строки, а не только в тот, в котором я сейчас нахожусь. Кажется, есть какая-то проблема с тем, как я получаю доступ к 2D-списку... какие-либо предложения? благодарю вас

def one_hot_encode(data_list, column):
    one_hot_list = [[]]
    different_elements = []

    for row in data_list[1:]:                  # count different elements
        if row[column] not in different_elements:
            different_elements.append(row[column])

    for i in range(len(different_elements)):   # set variable names
        one_hot_list[0].append(different_elements[i])

    vector = []                              # create list shape with zeroes
    for i in range(len(different_elements)):
        vector.append(0)
    for i in range(1460):
        one_hot_list.append(vector)

    ind_row = 1                                # encode 1 for each sample
    for row in data_list[1:]:
        index = different_elements.index(row[column])
        one_hot_list[ind_row][index] = 1     # mistake!! sets all rows to 1
        ind_row += 1

4 ответа

Решение

Ваша проблема проистекает из vector объект, который вы создаете для выполнения горячего кодирования; Вы создали один объект, а затем создали one_hot_list который содержит 1460 ссылок на один и тот же объект. Когда вы сделаете изменение в одной из строк, оно будет отражено во всех строках.

Быстрое решение было бы создать отдельные копии vector для каждой строки (см. Как клонировать или скопировать список?):

one_hot_list.append(vector[:])

Некоторые другие вещи, которые вы делаете в своей функции, немного медленные или обходные. Я бы предложил несколько изменений:

def one_hot_encode(data_list, column):
    one_hot_list = [[]]

    # count different elements
    different_elements = set(row[column] for row in data_list[1:])

    # convert different_elements to a list with a canonical order,
    # store in the first element of one_hot_list
    one_hot_list[0] = sorted(different_elements)

    vector = [0] * len(different_elements)   # create list shape with zeroes
    one_hot_list.extend([vector[:] for _ in range(1460)])

    # build a mapping of different_element values to indices into
    # one_hot_list[0]
    index_lookup = dict((e,i) for (i,e) in enumerate(one_hot_list[0]))
    # encode 1 for each sample
    for rindex, row in enumerate(data_list[1:], 1):
        cindex = index_lookup[row[column]]
        one_hot_list[rindex][cindex] = 1

Это строит different_elements в линейном времени с помощью set тип данных, и использует списки для получения значений для one_hot_list[0] (список значений элементов, которые подвергаются горячему кодированию), ноль vector, а также one_hot_list[1:] (которое является фактическим значением матрицы с горячим кодированием). Кроме того, есть dict называется index_lookup это позволяет вам быстро отображать значения элементов в их целочисленный индекс, а не искать их снова и снова. Наконец, ваш индекс строки в one_hot_list матрица может управляться для вас enumerate,

Вы можете использовать set() для подсчета уникальных предметов в списке

 different_elements = list(set(data[1:]))

Я предлагаю вам уберечь себя от необходимости повторной реализации этого на простом Python. Вы можете использовать использовать pandas.get_dummies за это:

Сначала некоторые тестовые данные (test.csv):

A
Foo
Bar
Baz

Тогда в Python:

import pandas as pd

df = pd.read_csv('test.csv')
# convert column 'A' to one-hot encoding
pd.get_dummies(df['A'])

Таблица

Вы можете получить основной numpy массив с использованием:

pd.get_dummies(df['A']).values

Что приводит к:

array([[0, 0, 1],
       [1, 0, 0],
       [0, 1, 0]], dtype=uint8)

Я не уверен на 100% в том, что вы пытаетесь сделать, но проблема, которую вы видите, заключается в следующих строках:

for i in range(1460):
    one_hot_list.append(vector)

Это создание one_hot_list 1460 ссылается на один и тот же вектор нулей. В то время как я думаю, что вы хотите, чтобы это было новым вектором каждый раз. Прямым решением будет просто копировать его каждый раз:

for i in range(1460):
    one_hot_list.append(vector[:])

Но более Pythonic подход будет создать список с пониманием. Возможно, что-то вроде этого:

vector_size = len(different_elements):
one_hot_list = [ [0] * vector_size for i in range(1460)]
Другие вопросы по тегам