Spec-Zone.ru › scikit-learn

8.4. Заполнение пропущенных значений

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

8.4.1. Одномерное и многомерное заполнение пропусков

Один из типов алгоритмов заполнения пропусков — одномерный: он заполняет значения в i-м измерении признака, используя только непропущенные значения в этом измерении (например, SimpleImputer). Напротив, многомерные алгоритмы заполнения пропусков используют весь набор доступных измерений признаков для оценки пропущенных значений (например, IterativeImputer).

8.4.2. Одномерное заполнение пропусков в признаках

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

В следующем фрагменте показано, как заменить пропущенные значения, закодированные как np.nan, средним значением столбцов (ось 0), содержащих пропущенные значения:

>>> import numpy as np
>>> from sklearn.impute import SimpleImputer
>>> imp = SimpleImputer(missing_values=np.nan, strategy='mean')
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
SimpleImputer()
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))
[[4.          2.        ]
 [6.          3.666]
 [7.          6.        ]]

Класс SimpleImputer также поддерживает разреженные матрицы:

>>> import scipy.sparse as sp
>>> X = sp.csc_array([[1, 2], [0, -1], [8, 4]])
>>> imp = SimpleImputer(missing_values=-1, strategy='mean')
>>> imp.fit(X)
SimpleImputer(missing_values=-1)
>>> X_test = sp.csc_array([[-1, 2], [6, -1], [7, 6]])
>>> print(imp.transform(X_test).toarray())
[[3. 2.]
 [6. 3.]
 [7. 6.]]

Обратите внимание, что этот формат не предназначен для неявного хранения пропущенных значений в матрице, поскольку во время преобразования она станет плотной. Для входных плотных данных следует использовать пропущенные значения, закодированные нулём.

Класс SimpleImputer также поддерживает категориальные данные, представленные строковыми значениями или категориальными данными pandas, при использовании стратегий 'most_frequent' или 'constant':

>>> import pandas as pd
>>> df = pd.DataFrame([["a", "x"],
...                    [np.nan, "y"],
...                    ["a", np.nan],
...                    ["b", "y"]], dtype="category")
...
>>> imp = SimpleImputer(strategy="most_frequent")
>>> print(imp.fit_transform(df))
[['a' 'x']
 ['a' 'y']
 ['a' 'y']
 ['b' 'y']]

Другой пример использования см. в разделе Заполнение пропущенных значений перед созданием оценивателя.

8.4.3. Многомерное заполнение пропусков в признаках

Более сложный подход — использовать класс IterativeImputer, который моделирует каждый признак с пропущенными значениями как функцию других признаков и использует эту оценку для заполнения пропусков. Это выполняется итеративно, по круговой схеме: на каждом шаге один столбец признака назначается выходным y, а остальные столбцы признаков рассматриваются как входные данные X. Регрессор обучается на (X, y) для известных y. Затем регрессор используется для предсказания пропущенных значений y. Эта процедура итеративно выполняется для каждого признака, а затем повторяется в течение max_iter раундов заполнения. Возвращаются результаты последнего раунда заполнения.

Примечание

Пока этот оцениватель всё ещё имеет статус экспериментального: параметры по умолчанию и детали поведения могут измениться без периода устаревания. Решение следующих проблем помогло бы стабилизировать IterativeImputer: критерии сходимости (#14338) и оцениватели по умолчанию (#13286). Чтобы использовать его, необходимо явно импортировать enable_iterative_imputer.

>>> import numpy as np
>>> from sklearn.experimental import enable_iterative_imputer
>>> from sklearn.impute import IterativeImputer
>>> imp = IterativeImputer(max_iter=10, random_state=0)
>>> imp.fit([[1, 2], [3, 6], [4, 8], [np.nan, 3], [7, np.nan]])
IterativeImputer(random_state=0)
>>> X_test = [[np.nan, 2], [6, np.nan], [np.nan, 6]]
>>> # the model learns that the second feature is double the first
>>> print(np.round(imp.transform(X_test)))
[[ 1.  2.]
 [ 6. 12.]
 [ 3.  6.]]

И SimpleImputer, и IterativeImputer можно использовать в Pipeline для создания составного оценивателя, поддерживающего заполнение пропусков. См. раздел Заполнение пропущенных значений перед созданием оценивателя.

8.4.3.1. Гибкость IterativeImputer

В экосистеме анализа данных R существует множество хорошо зарекомендовавших себя пакетов для заполнения пропусков: Amelia, mi, mice, missForest и другие. missForest популярен и, как оказалось, является частным случаем различных алгоритмов последовательного заполнения, которые можно реализовать с помощью IterativeImputer, передавая разные регрессоры для предсказания пропущенных значений признаков. В missForest в качестве регрессора используется Random Forest. См. раздел Заполнение пропущенных значений вариантами IterativeImputer.

8.4.3.2. Множественное и однократное заполнение пропусков

В статистике принято выполнять множественное заполнение пропусков, например создавая m отдельных вариантов заполнения для одной матрицы признаков. Затем каждый из этих m вариантов заполнения проходит последующий аналитический конвейер (например, конструирование признаков, кластеризацию, регрессию, классификацию). m Итоговые результаты анализа (например, ошибки на отложенной выборке) позволяют специалисту по анализу данных понять, как аналитические результаты могут меняться из-за неопределённости, обусловленной пропущенными значениями. Эта практика называется множественным заполнением пропусков.

Наша реализация IterativeImputer вдохновлена пакетом R MICE (Multivariate Imputation by Chained Equations) [1], но отличается тем, что возвращает один вариант заполнения, а не несколько. Однако IterativeImputer также можно использовать для множественного заполнения, многократно применяя его к одному и тому же набору данных с разными случайными начальными значениями, если sample_posterior=True. Дополнительное обсуждение множественного и однократного заполнения см. в главе 4 источника [2].

Вопрос о том, насколько полезно однократное или множественное заполнение при прогнозировании и классификации, остаётся открытым, если пользователь не заинтересован в оценке неопределённости, связанной с пропущенными значениями.

Обратите внимание, что вызов метода transform у IterativeImputer не может изменить количество образцов. Поэтому выполнить множественное заполнение одним вызовом transform невозможно.

Литература

[1]

Stef van Buuren, Karin Groothuis-Oudshoorn (2011). “mice: Multivariate Imputation by Chained Equations in R”. Journal of Statistical Software 45: 1-67.

[2]

Roderick J A Little и Donald B Rubin (1986). “Statistical Analysis with Missing Data”. John Wiley & Sons, Inc., New York, NY, USA.

8.4.4. Заполнение пропусков методом ближайших соседей

Класс KNNImputer заполняет пропущенные значения с помощью метода k ближайших соседей. По умолчанию для поиска ближайших соседей используется метрика евклидова расстояния, поддерживающая пропущенные значения, nan_euclidean_distances. Каждый пропущенный признак заполняется значениями n_neighbors ближайших соседей, у которых есть значение этого признака. Значения признака у соседей усредняются равномерно или взвешиваются по расстоянию до каждого соседа. Если у образца пропущено несколько признаков, то для этого образца могут выбираться разные соседи в зависимости от конкретного заполняемого признака. Если доступных соседей меньше n_neighbors и расстояния до обучающего набора не определены, при заполнении используется среднее значение этого признака в обучающем наборе. Если хотя бы у одного соседа расстояние определено, при заполнении используется взвешенное или невзвешенное среднее значение остальных соседей. Если признак всегда пропущен в обучающих данных, он удаляется во время transform. Подробнее о методике см. источник [OL2001].

В следующем фрагменте показано, как заменить пропущенные значения, закодированные как np.nan, средним значением признака у двух ближайших соседей образцов с пропущенными значениями:

>>> import numpy as np
>>> from sklearn.impute import KNNImputer
>>> nan = np.nan
>>> X = [[1, 2, nan], [3, 4, 3], [nan, 6, 5], [8, 8, 7]]
>>> imputer = KNNImputer(n_neighbors=2, weights="uniform")
>>> imputer.fit_transform(X)
array([[1. , 2. , 4. ],
       [3. , 4. , 3. ],
       [5.5, 6. , 5. ],
       [8. , 8. , 7. ]])

Другой пример использования см. в разделе Заполнение пропущенных значений перед созданием оценивателя.

Литература

[OL2001]

Olga Troyanskaya, Michael Cantor, Gavin Sherlock, Pat Brown, Trevor Hastie, Robert Tibshirani, David Botstein и Russ B. Altman, Missing value estimation methods for DNA microarrays, BIOINFORMATICS Vol. 17 no. 6, 2001 Pages 520-525.

8.4.5. Сохранение постоянного числа признаков

По умолчанию средства заполнения пропусков scikit-learn удаляют полностью пустые признаки, то есть столбцы, содержащие только пропущенные значения. Например:

>>> imputer = SimpleImputer()
>>> X = np.array([[np.nan, 1], [np.nan, 2], [np.nan, 3]])
>>> imputer.fit_transform(X)
array([[1.],
       [2.],
       [3.]])

Первый признак в X, содержащий только np.nan, был удалён после заполнения пропусков. Хотя этот признак не поможет при прогнозировании, удаление столбцов изменит форму X, что может быть проблемой при использовании средств заполнения пропусков в более сложном конвейере машинного обучения. Параметр keep_empty_features позволяет сохранить пустые признаки, заполнив их постоянным значением. В большинстве случаев это значение равно нулю:

>>> imputer.set_params(keep_empty_features=True)
SimpleImputer(keep_empty_features=True)
>>> imputer.fit_transform(X)
array([[0., 1.],
       [0., 2.],
       [0., 3.]])

8.4.6. Маркировка заполненных значений

Преобразователь MissingIndicator полезен для преобразования набора данных в соответствующую двоичную матрицу, указывающую наличие пропущенных значений в наборе данных. Это преобразование полезно в сочетании с заполнением пропусков. При заполнении пропусков может быть полезно сохранить информацию о том, какие значения отсутствовали. Обратите внимание, что у SimpleImputer и IterativeImputer есть логический параметр add_indicator (по умолчанию False). Если задать ему значение True, он предоставит удобный способ объединить выходные данные преобразователя MissingIndicator с выходными данными средства заполнения пропусков.

Обычно для представления пропущенных значений используется NaN. Однако это требует использования типа данных float. Параметр missing_values позволяет задать другой маркер, например целое число. В следующем примере в качестве пропущенных значений используется -1:

>>> from sklearn.impute import MissingIndicator
>>> X = np.array([[-1, -1, 1, 3],
...               [4, -1, 0, -1],
...               [8, -1, 1, 0]])
>>> indicator = MissingIndicator(missing_values=-1)
>>> mask_missing_values_only = indicator.fit_transform(X)
>>> mask_missing_values_only
array([[ True,  True, False],
       [False,  True,  True],
       [False,  True, False]])

Параметр features используется для выбора признаков, для которых строится маска. По умолчанию задано значение 'missing-only', которое возвращает маску средства заполнения для признаков, содержащих пропущенные значения на момент fit:

>>> indicator.features_
array([0, 1, 3])

Параметру features можно присвоить значение 'all', чтобы возвращать все признаки, независимо от того, содержат ли они пропущенные значения:

>>> indicator = MissingIndicator(missing_values=-1, features="all")
>>> mask_all = indicator.fit_transform(X)
>>> mask_all
array([[ True,  True, False, False],
       [False,  True, False,  True],
       [False,  True, False, False]])
>>> indicator.features_
array([0, 1, 2, 3])

При использовании MissingIndicator в Pipeline не забудьте использовать FeatureUnion или ColumnTransformer, чтобы добавить признаки-индикаторы к обычным признакам. Сначала получим набор данных iris и добавим в него несколько пропущенных значений.

>>> from sklearn.datasets import load_iris
>>> from sklearn.impute import SimpleImputer, MissingIndicator
>>> from sklearn.model_selection import train_test_split
>>> from sklearn.pipeline import FeatureUnion, make_pipeline
>>> from sklearn.tree import DecisionTreeClassifier
>>> X, y = load_iris(return_X_y=True)
>>> mask = np.random.randint(0, 2, size=X.shape).astype(bool)
>>> X[mask] = np.nan
>>> X_train, X_test, y_train, _ = train_test_split(X, y, test_size=100,
...                                                random_state=0)

Теперь создадим FeatureUnion. Все признаки будут заполнены с помощью SimpleImputer, чтобы классификаторы могли работать с этими данными. Кроме того, будут добавлены переменные-индикаторы из MissingIndicator.

>>> transformer = FeatureUnion(
...     transformer_list=[
...         ('features', SimpleImputer(strategy='mean')),
...         ('indicators', MissingIndicator())])
>>> transformer = transformer.fit(X_train, y_train)
>>> results = transformer.transform(X_test)
>>> results.shape
(100, 8)

Разумеется, мы не можем использовать преобразователь для выполнения предсказаний. Чтобы получить возможность выполнять предсказания, его следует обернуть в Pipeline вместе с классификатором (например, DecisionTreeClassifier).

>>> clf = make_pipeline(transformer, DecisionTreeClassifier())
>>> clf = clf.fit(X_train, y_train)
>>> results = clf.predict(X_test)
>>> results.shape
(100,)

8.4.7. Оцениватели, работающие со значениями NaN

Некоторые оцениватели предназначены для работы со значениями NaN без предварительной обработки. Ниже приведён список таких оценивателей, сгруппированных по типу (кластеризация, регрессия, классификация, преобразование):

  • Оцениватели, допускающие значения NaN для типа cluster:
    • HDBSCAN
  • Оцениватели, допускающие значения NaN для типа regressor:
    • BaggingRegressor
    • DecisionTreeRegressor
    • ExtraTreeRegressor
    • ExtraTreesRegressor
    • HistGradientBoostingRegressor
    • RandomForestRegressor
    • StackingRegressor
    • VotingRegressor
  • Оцениватели, допускающие значения NaN для типа classifier:
    • BaggingClassifier
    • DecisionTreeClassifier
    • ExtraTreeClassifier
    • ExtraTreesClassifier
    • HistGradientBoostingClassifier
    • RandomForestClassifier
    • StackingClassifier
    • VotingClassifier
  • Оцениватели, допускающие значения NaN для типа transformer:
    • IterativeImputer
    • KNNImputer
    • MaxAbsScaler
    • MinMaxScaler
    • MissingIndicator
    • OneHotEncoder
    • OrdinalEncoder
    • PowerTransformer
    • QuantileTransformer
    • RandomTreesEmbedding
    • RobustScaler
    • SimpleImputer
    • SplineTransformer
    • StackingClassifier
    • StackingRegressor
    • StandardScaler
    • TargetEncoder
    • VarianceThreshold
    • VotingClassifier
    • VotingRegressor

© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/modules/impute.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API