В этом проекте я буду анализировать данные переписи из репозитория машинного обучения UCI, которые я получил отсюда, и классифицировать данные на основе дохода гражданина. Эти данные были взяты из базы данных Бюро переписи населения США.

Я использую файл adult.data, который содержит следующие столбцы:

  • возраст: непрерывный.
  • рабочий класс: частный, Self-emp-not-inc, Self-emp-inc, Federal-gov, Local-gov, State-gov, без оплаты, никогда не работал.
  • fnlwgt: непрерывный.
  • образование: бакалавриат, некоторый колледж, 11-й, высшая степень, проф-школа, ассоц-акдм, ассоц-вок, 9-й, 7-8-й, 12-й, магистр, 1-4-й, 10-й, докторантура, 5-й-6-й, дошкольное.
  • номер образования: непрерывное.
  • семейное положение: Женат-гражданский-супруг, Разведен, Никогда не состоял в браке, Раздельно, Вдовец, Женат-супруг-отсутствует, Женат-AF-супруга.
  • профессия: Техподдержка, Ремесло-ремонт, Прочее-обслуживание, Продажи, Исполнитель-менеджер, Проф-специальность, Обработчики-уборщики, Машино-осмотр, Адм-канцелярия, Фермерство-рыболовство, Транспорт-переезд, Приват- серв, Защитно-серв, Вооруженные Силы.
  • Отношения: Жена, Собственный ребенок, Муж, Вне семьи, Другой родственник, Неженатый.
  • раса: Белый, Азиатско-Пакско-Айлендерианец, Амерско-Индейско-Эскимосский, Другой, Черный.
  • пол: Женский, Мужской.
  • прирост капитала: непрерывный.
  • убыток капитала: непрерывный.
  • часов в неделю: непрерывно.
  • родная страна: США, Камбоджа, Англия, Пуэрто-Рико, Канада, Германия, отдаленные районы США (Гуам-USVI-и т. д.), Индия, Япония, Греция, Юг, Китай, Куба, Иран, Гондурас, Филиппины, Италия , Польша, Ямайка, Вьетнам, Мексика, Португалия, Ирландия, Франция, Доминиканская Республика, Лаос, Эквадор, Тайвань, Гаити, Колумбия, Венгрия, Гватемала, Никарагуа, Шотландия, Таиланд, Югославия, Сальвадор, Тринадад и Тобаго, Перу, Гонконг , Голландия-Нидерланды.
  • доход: ›50K, ‹=50K.

В этом проекте я буду использовать классификатор XGBoost. Шаги, которые я сделаю:

  • Исследовательский анализ данных
  • Построение модели
  • Обучение модели
  • Улучшение модели

Исследовательский анализ данных

Я загружаю данные из источника и помещаю их в переменную df.

import requests
import io
col = ['age','workclass','fnlwgt','education','education-num','marital-status','occupation','relationship','race','sex','capital-gain','capital-loss','hours-per-week','native-country','income']
s = requests.get('https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data', verify=False)
df = pd.read_csv(io.StringIO(s.content.decode('utf-8')),delimiter=",",names=col,skipinitialspace=True)

Обзор данных показан ниже.

Давайте получим больше информации о данных, используя df.info().

RangeIndex: 32561 entries, 0 to 32560
Data columns (total 15 columns):
 #   Column          Non-Null Count  Dtype 
---  ------          --------------  ----- 
 0   age             32561 non-null  int64 
 1   workclass       32561 non-null  object
 2   fnlwgt          32561 non-null  int64 
 3   education       32561 non-null  object
 4   education-num   32561 non-null  int64 
 5   marital-status  32561 non-null  object
 6   occupation      32561 non-null  object
 7   relationship    32561 non-null  object
 8   race            32561 non-null  object
 9   sex             32561 non-null  object
 10  capital-gain    32561 non-null  int64 
 11  capital-loss    32561 non-null  int64 
 12  hours-per-week  32561 non-null  int64 
 13  native-country  32561 non-null  object
 14  income          32561 non-null  object
dtypes: int64(6), object(9)
memory usage: 3.7+ MB

Данные содержат 32561 запись. Все записи не являются нулевыми во всех столбцах. Есть 14 столбцов (признаков), 6 столбцов числовых с типом целых чисел, остальные (категориальные) с типом объекта.

Давайте посмотрим описательную статистику числовых столбцов, используя df.describe().

Для категориальных столбцов количество категорий каждого столбца может быть показано с помощью df.unique() , который возвращает

age                  73
workclass             9
fnlwgt            21648
education            16
education-num        16
marital-status        7
occupation           15
relationship          6
race                  5
sex                   2
capital-gain        119
capital-loss         92
hours-per-week       94
native-country       42
income                2
dtype: int64

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

print('These are the income categories: %s' % (pd.unique(df['income'])))
for i in pd.unique(df['income']):
print('%.2f%% people have income %s' %(df['income'][df['income']==i].count()/df['income'].count()*100,i))

Выходы

These are the income categories: ['<=50K' '>50K']
75.92% people have income <=50K
24.08% people have income >50K

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

df[df.select_dtypes(include=['int64', 'float64']).columns].hist(figsize=(15,10))
plt.show()

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

Давайте посмотрим на детали столбца education-num и столбца education , поскольку оба имеют одинаковое имя, используя print(df[['education-num'],['education']]) , что приводит к выводу ниже.

       education-num   education
0                 13   Bachelors
1                 13   Bachelors
2                  9     HS-grad
3                  7        11th
4                 13   Bachelors
...              ...         ...
32556             12  Assoc-acdm
32557              9     HS-grad
32558              9     HS-grad
32559              9     HS-grad
32560              9     HS-grad

Число образования — это количество лет, потраченных на чье-то образование. Люди с одинаковым образованием также имеют одинаковый номер образования. Так что функция образования избыточна. Некоторые символы в имени столбца изменены. Столбец fnlwgt также удален, поскольку он не имеет отношения к переписываемому лицу. Я удаляю эти столбцы, используя этот код

df=df.drop(['education'], axis=1)
df=df.drop(['fnlwgt'], axis=1)

Поскольку у нас есть 8 нечисловых признаков, мы должны преобразовать их в числовые.

df=pd.get_dummies(df)
df.rename(columns = {'income_<=50K':'income_less=50K', 'income_>50K':'income_greater50K'}, inplace = True)

Здесь я использую манекены для создания дополнительных функций, которые являются вариациями записей нечисловых функций. Эти дополнительные функции состоят только из значений 1 и 0. Теперь у нас есть 92 функции.

Построение модели

Столбец дохода, который имеет только два значения, теперь преобразуется в два столбца, каждый из которых имеет одинаковое значение, представляющее столбец дохода. Мы можем удалить один из них, используя df=df.drop(“income_less=50K”,axis=1) .

Затем столбцы функций загружаются в x, а целевой столбец «доход_›50K» загружается в y. Переменная x также стандартизирована и масштабирована.

from sklearn.preprocessing import StandardScaler
scaler=StandardScaler()
x=df.iloc[:,:-1]
y=df.iloc[:,-1]
x=scaler.fit_transform(x)

Затем функции были разделены на данные поезда, тестовые данные и данные проверки.

from sklearn.model_selection import train_test_split
x_train_a, x_test, y_train_a, y_test=train_test_split(x,y,random_state=0)
x_train, x_val, y_train, y_val=train_test_split(x_train_a, y_train_a, random_state=0)

Следующим шагом является построение модели. Я выбираю метод XGBoost, потому что он относительно быстрый и имеет хорошую производительность, особенно при обработке несбалансированных данных для двоичной классификации. Он также часто используется в ML-сообществе. Я использую LogLoss в качестве метрики оценки, потому что она обычно используется при оценке прогнозируемых вероятностей.

from xgboost import XGBClassifier
xgb=XGBClassifier(n_estimators=500, learning_rate=.05, use_label_encoder=False, eval_metric='logloss', early_stopping_rounds=5, n_jobs=-1)

Теперь давайте подгоним модель к данным поезда.

xgb.fit(x_train, y_train, eval_set=[(x_val, y_val)], verbose=False)

Далее давайте проверим точность модели, подгоняя модель к тестовым данным.

from sklearn.metrics import accuracy_score
ypredtest = xgb.predict(x_test)
predtestscore = accuracy_score(ypredtest, y_test)

Тест точности возвращает результат со значением 0,87. Здесь мы знаем, что метод XGBoost, имеющий оценку 0,87. Судя по баллам, эта модель работает достаточно хорошо.

Улучшение модели

В этой части я попытаюсь улучшить модель, уменьшив размерность данных. Уменьшая размерность данных, мы можем избавиться от ненужных функций. Я попытаюсь использовать методы анализа основных компонентов и анализа множественных соответствий.

Во-первых, я использую метод PCA (анализ основных компонентов), чтобы уменьшить количество функций. Я применил его к фрейму данных, который превратился во все числовые данные. Метод PCA подходит для числовых и двоичных данных. Но многие функции в преобразованном фрейме данных, которые у меня есть, представляют его исходные категориальные функции, поэтому их нельзя удалить/уменьшить. Я попробовал этот метод, чтобы уменьшить размер данных до 60.

from sklearn.decomposition import PCA
pca = PCA(n_components = 60)
x_trainp = pca.fit_transform(x_train_a)
x_testp = pca.transform(x_test)
x_train, x_val, y_train, y_val=train_test_split(x_trainp, y_train_a, random_state=0)
xgb.fit(x_train, y_train, eval_set=[(x_val, y_val)], verbose=False)
ypredtest = xgb.predict(x_testp)
predtestscore = accuracy_score(ypredtest, y_test)
print("Test score:", np.round(predtestscore,2))

После уменьшения характеристик я получил оценку 0,85. Таким образом, модель не подходит лучше, чем исходные данные, потому что она набирает меньше баллов.

Другим вариантом уменьшения размерности данных (уменьшения признака) является MCA (анализ множественных соответствий), поскольку его можно использовать и для категориальных данных.

!pip install prince
import prince
mca = prince.MCA(n_components=2, n_iter=3, copy=True, check_input=True, engine='auto', random_state=42)
DF_mca = mca.fit(DF)
ax = DF_mca.plot_coordinates(X=DF, ax=None, figsize=(8, 10), show_row_points=False, row_points_size=0, show_row_labels=False, show_column_points=True, column_points_size=30, show_column_labels=True, legend_n_cols=1 ).legend(loc='center left', bbox_to_anchor=(1, 0.5))

График MCA показывает, что прирост капитала, убыток капитала и жители Нидерландов относительно не связаны с доходом. Таким образом, функция прироста капитала и потери капитала может быть удалена.

df=DF
df=pd.get_dummies(df)
df. rename(columns = {'income_<=50K':'income_less=50K', 'income_>50K':'income_greater50K'}, inplace = True)
df=df.drop("income_less=50K",axis=1)
df=df.drop("capital-loss",axis=1)
df=df.drop("capital-gain",axis=1)
from sklearn.preprocessing import StandardScaler
scaler=StandardScaler()
x=df.iloc[:,:-1]
y=df.iloc[:,-1]
x=scaler.fit_transform(x)
x_train_a, x_test, y_train_a, y_test=train_test_split(x,y,random_state=0)
x_train, x_val, y_train, y_val=train_test_split(x_train_a, y_train_a, random_state=0)
xgb.fit(x_train, y_train, eval_set=[(x_val, y_val)], verbose=False)
ypredtest = xgb.predict(x_test)
predtestscore = accuracy_score(ypredtest, y_test)
print("Test score:", np.round(predtestscore,2))

Здесь мы получили 0,84 в качестве оценки модели. По результатам теста видно, что эта модель достаточно хороша, но не лучше оригинала. Сокращение функций иногда не приводит нас к лучшей модели.

В заключение мы провели классификацию данных переписи населения с использованием метода XGBoost. Метод XGBoost имеет оценку 0,87, что означает, что эта модель работает достаточно хорошо. Мы попытались улучшить модель, уменьшив характеристики данных, но это не дает лучшего результата.

Полный код можно посмотреть здесь.

Источник: