LabelEncoder, который хранит пропущенные значения как «NaN» - PullRequest
0 голосов
/ 30 января 2019

Я пытаюсь использовать кодировщик меток в orrder для преобразования категориальных данных в числовые значения.

Мне нужен LabelEncoder, который сохраняет мои пропущенные значения как «NaN», чтобы впоследствии использовать Imputer.Поэтому я хотел бы использовать маску для замены формы исходного фрейма данных после маркировки следующим образом:

df = pd.DataFrame({'A': ['x', np.NaN, 'z'], 'B': [1, 6, 9], 'C': [2, 1, np.NaN]})


    A   B   C
0   x   1   2.0
1   NaN 6   1.0
2   z   9   NaN


dfTmp = df
mask = dfTmp.isnull()

       A    B   C
0   False   False   False
1   True    False   False
2   False   False   True

. Таким образом, я получаю фрейм данных со значением True / false

. Затем создайте кодировщик.:

df = df.astype(str).apply(LabelEncoder().fit_transform)

Как я могу продолжить, чтобы кодировать эти значения?

спасибо

1 Ответ

0 голосов
/ 31 января 2019

Первый вопрос: хотите ли вы кодировать каждый столбец отдельно или кодировать их все одной кодировкой?

Выражение df = df.astype(str).apply(LabelEncoder().fit_transform) подразумевает, что вы кодируете все столбцы по отдельности.

That case you can do the following:
df = df.apply(lambda series: pd.Series(
    LabelEncoder().fit_transform(series[series.notnull()]),
    index=series[series.notnull()].index
))
print(df)
Out:
     A  B    C
0  0.0  0  1.0
1  NaN  1  0.0
2  1.0  2  NaN

объяснение того, как это работает ниже.Но для начала я расскажу о нескольких недостатках этого решения.

Недостатки
Во-первых, существуют смешанные типы столбцов: если столбец содержит NaN значение, тогда столбец имеет тип float, потому что nan's - это числа с плавающей запятой в python.

df.dtypes
A    float64
B      int64
C    float64
dtype: object

Кажется, для меток это бессмысленно.Хорошо, позже вы можете игнорировать все наны и преобразовать остальные в целое число.

Второй момент: вероятно, вам нужно запомнить LabelEncoder - потому что часто требуется, например, сделать обратное преобразование.Но это решение не запоминает кодировщики, у вас нет такой возможности.

Простое, явное решение:

encoders = dict()

for col_name in df.columns:
    series = df[col_name]
    label_encoder = LabelEncoder()
    df[col_name] = pd.Series(
        label_encoder.fit_transform(series[series.notnull()]),
        index=series[series.notnull()].index
    )
    encoders[col_name] = label_encoder

print(df)
Out:
     A  B    C
0  0.0  0  1.0
1  NaN  1  0.0
2  1.0  2  NaN

- больше кода, но результат тот же

print(encoders)
Out
{'A': LabelEncoder(), 'B': LabelEncoder(), 'C': LabelEncoder()}

- также доступны кодеры.Обратное преобразование (должно быть также удалено до Nan!):

encoders['B'].inverse_transform(df['B'])
Out:
array([1, 6, 9])

Кроме того, некоторые опции, такие как некоторый суперкласс реестра для кодировщиков, также доступны, и они совместимы с первым решением, но их легче перебирать по столбцам.

Как это работает

df.apply(lambda series: ...) применяет функцию, которая возвращает pd.Series для каждого столбца;таким образом, он возвращает фрейм данных с новыми значениями.

Выражение шаг за шагом:

pd.Series(
    LabelEncoder().fit_transform(series[series.notnull()]),
    index=series[series.notnull()].index
)

- series[series.notnull()] отбрасывает NaN значений, затем передает остаток в fit_transform.

- поскольку кодировщик меток возвращает numpy.array и выбрасывает индекс, index=series[series.notnull()].index восстанавливает его для правильной конкатенации.Если не выполнять индексацию:

print(df)
Out:
     A  B    C
0    x  1  2.0
1  NaN  6  1.0
2    z  9  NaN
df = df.apply(lambda series: pd.Series(
    LabelEncoder().fit_transform(series[series.notnull()]),
))
print(df)
Out:
     A  B    C
0  0.0  0  1.0
1  1.0  1  0.0
2  NaN  2  NaN

- значения смещаются от правильных позиций - и даже может IndexError.

Один кодировщик для всех столбцов

В этом случае стекируйте фрейм данных, подгоняйте кодировку, затем снимайте ее

series_stack = df.stack().astype(str)
label_encoder = LabelEncoder()
df = pd.Series(
    label_encoder.fit_transform(series_stack),
    index=series_stack.index
).unstack()
print(df)
Out:
     A    B    C
0  5.0  0.0  2.0
1  NaN  3.0  1.0
2  6.0  4.0  NaN

- так как series_stack равен pd.Series, содержащему NaN, все значения из DataFrame являются плавающими, так что вы можете предпочесть конвертировать его.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...