Эффект масштабирования объектов, когда NaN установлены на -1

1

У меня есть набор данных, содержащий некоторые функции с довольно большим количеством NaN (до 80%). Удаление их, исказило бы мой общий дистрибутив, поэтому мои варианты - установить все NaN на -1 / - 99 или вывести мою непрерывную переменную в группы, что делает ее категориальной.

Поскольку у меня уже есть много категориальных функций, я бы предпочел не делать несколько непрерывных, категоричных тоже. Однако, если я установил NaN на -1 / - 99, это существенно повлияет на результаты, когда я масштабирую эти функции?

Или с другой точки зрения, есть ли способ масштабирования функций, если -1 слишком сильно влияет на его масштабирование?

Теги:
scaling
nan

1 ответ

1
Лучший ответ

Я знаю, что вы получили ответ из комментариев выше, но, пытаясь показать новым пользователям scikit-learn, как вы могли бы подойти к такой проблеме, я собрал очень рудиментарное решение, демонстрирующее, как создать настраиваемый трансформатор, который будет справляться с этим:

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils.validation import check_array, check_is_fitted
import numpy as np

class NanImputeScaler(BaseEstimator, TransformerMixin):
    """Scale an array with missing values, then impute them
    with a dummy value. This prevents the imputed value from impacting
    the mean/standard deviation computation during scaling.

    Parameters
    ----------
    with_mean : bool, optional (default=True)
        Whether to center the variables.

    with_std : bool, optional (default=True)
        Whether to divide by the standard deviation.

    nan_level : int or float, optional (default=-99.)
        The value to impute over NaN values after scaling the other features.
    """
    def __init__(self, with_mean=True, with_std=True, nan_level=-99.):
        self.with_mean = with_mean
        self.with_std = with_std
        self.nan_level = nan_level

    def fit(self, X, y=None):
        # Check the input array, but don't force everything to be finite.
        # This also ensures the array is 2D
        X = check_array(X, force_all_finite=False, ensure_2d=True)

        # compute the statistics on the data irrespective of NaN values
        self.means_ = np.nanmean(X, axis=0)
        self.std_ = np.nanstd(X, axis=0)
        return self

    def transform(self, X):
        # Check that we have already fit this transformer
        check_is_fitted(self, "means_")

        # get a copy of X so we can change it in place
        X = check_array(X, force_all_finite=False, ensure_2d=True)

        # center if needed
        if self.with_mean:
            X -= self.means_
        # scale if needed
        if self.with_std:
            X /= self.std_

        # now fill in the missing values
        X[np.isnan(X)] = self.nan_level
        return X

Способ, которым это работает, заключается в вычислении nanmean и nanstd в секции fit так что значения NaN игнорируются при вычислении статистики. Затем, в секции transform, после того, как переменные масштабируются и центрируются, оставшиеся значения NaN вменяются значением, которое вы назначили (вы упоминали -99, так что то, что я сделал по умолчанию). Вы всегда можете сломать этот компонент трансформатора в другой трансформатор, но я включил его только для демонстрационных целей.

Пример в действии:

Здесь мы установим некоторые данные с присутствием NaN:

nan = np.nan
data = np.array([
    [ 1., nan,  3.],
    [ 2.,  3., nan],
    [nan,  4.,  5.],
    [ 4.,  5.,  6.]
])

И когда мы подходим к скалеру и изучаем средние/стандартные отклонения, вы можете видеть, что они не учитывали значения NaN:

>>> imputer = NanImputeScaler().fit(data)
>>> imputer.means_
array([ 2.33333333,  4.        ,  4.66666667])
>>> imputer.std_
array([ 1.24721913,  0.81649658,  1.24721913])

Наконец, когда мы преобразуем данные, данные масштабируются и обрабатываются значения NaN:

>>> imputer.transform(data)
array([[ -1.06904497, -99.        ,  -1.33630621],
       [ -0.26726124,  -1.22474487, -99.        ],
       [-99.        ,   0.        ,   0.26726124],
       [  1.33630621,   1.22474487,   1.06904497]])

Pipelining

Вы даже можете использовать этот шаблон внутри конвейера scikit-learn (и даже сохраняете его на диске):

from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
pipe = Pipeline([
        ("scale", NanImputeScaler()),
        ("clf", LogisticRegression())
    ]).fit(data, y)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню