IIS_2023_1/kochkareva_elizaveta_lab_4/README.md
2023-11-24 15:28:14 +04:00

24 KiB
Raw Blame History

Лабораторная работа 4. Вариант 15

Задание

Использовать алгоритм кластеризации K-means, самостоятельно сформулировав задачу. Интерпретировать результаты и оценить, насколько хорошо он подходит для решения сформулированной задачи.

Как запустить лабораторную работу

Для запуска программы необходимо с помощью командной строки в корневой директории файлов прокета прописать:

python main.py

Какие технологии использовали

  • Библиотека numpy для работы с массивами.
  • Библиотека pandas для работы с данными в формате таблицы.
  • Библиотека matplotlib pyplot - для визуализации данных.
  • Библиотека sklearn:
    • KMeans для использования алгоритма кластеризации K-средних.
    • train_test_split для разделения набора данных на обучающую и тестовую выборки.
    • LinearRegression для создания и работы с моделью Линейной регрессии.
    • RFE для рекурсивного отбора признаков

Описание лабораторной работы

Сформулированная задача

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

Оценка важности параметров

Прежде, чем перейти к решению поставленной задачи. Произведем анализ важности параметров, чтобы выделить наиболее существенные характеристики, которые влияют на выделение лакаций с похожиим характеристиками. Для этого создадим функцию recursive_feature_elimination(), где создаем копию исходного датафрейма data и присваивается переменной df. В df удаляем столбцы "Country" и "location" с помощью метода drop(), т.к. на данных столбца "Country" будем использовать как целеввые значения (заранее пропишем y = data['Country'] общий для всех функций, которые создадим в дальнейшем). Данные разделяем на обучающую и тестовую выборки с использованием функции train_test_split(). Размер тестовой выборки составляет 20% от исходных данных. Разделенные данные сохраняются в переменные X_train, X_test, y_train и y_test. Задаем имена столбцов датасета в переменной column_names, которые будем использовать для вывода данных. Далее для ранжирования важности параметров создаем экземпляры модели линейной регрессии LinearRegression() и модели RFE, которую обучаем на обучающих данных с помощью метода fit(). Для сортировки полученных результатов воспользуемся функцией rank_to_dict_rfe(ranking, names) из прошлой лабораторной работы.

def recursive_feature_elimination():
    df = data.copy()
    df.drop(["Country", "location"], axis=1, inplace=True)
    X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.2)
    column_names = ['Qualifications', 'Work Type', 'Company Size', 'Preference', 'Job Title', 'Role', 'Job Portal',
                    'skills', 'Company', 'Min Experience', 'Max Experience', 'Min Salary',
                    'Max Salary', 'Sector', 'Industry', 'City', 'State', 'Ticker', 'year', 'month', 'day',
                    "'Casual Dress Code, Social and Recreational Activities, Employee Referral Programs, Health and Wellness Facilities, Life and Disability Insurance'",
                    "'Childcare Assistance, Paid Time Off (PTO), Relocation Assistance, Flexible Work Arrangements, Professional Development'",
                    "'Employee Assistance Programs (EAP), Tuition Reimbursement, Profit-Sharing, Transportation Benefits, Parental Leave'",
                    "'Employee Referral Programs, Financial Counseling, Health and Wellness Facilities, Casual Dress Code, Flexible Spending Accounts (FSAs)'",
                    "'Flexible Spending Accounts (FSAs), Relocation Assistance, Legal Assistance, Employee Recognition Programs, Financial Counseling'",
                    "'Health Insurance, Retirement Plans, Flexible Work Arrangements, Employee Assistance Programs (EAP), Bonuses and Incentive Programs'",
                    "'Health Insurance, Retirement Plans, Paid Time Off (PTO), Flexible Work Arrangements, Employee Assistance Programs (EAP)'",
                    "'Legal Assistance, Bonuses and Incentive Programs, Wellness Programs, Employee Discounts, Retirement Plans'",
                    "'Life and Disability Insurance, Stock Options or Equity Grants, Employee Recognition Programs, Health Insurance, Social and Recreational Activities'",
                    "'Transportation Benefits, Professional Development, Bonuses and Incentive Programs, Profit-Sharing, Employee Discounts'",
                    "'Tuition Reimbursement, Stock Options or Equity Grants, Parental Leave, Wellness Programs, Childcare Assistance'"]

    estimator = LinearRegression()
    rfe_model = RFE(estimator)
    rfe_model.fit(X_train.values, y_train.values)
    ranks = rank_to_dict_rfe(rfe_model.ranking_, column_names)
    sorted_dict = dict(sorted(ranks.items(), key=lambda x: x[1], reverse=True))
    print(sorted_dict)

def rank_to_dict_rfe(ranking, names):
    n_ranks = [float(1 / i) for i in ranking]
    n_ranks = map(lambda x: round(x, 2), n_ranks)
    return dict(zip(names, n_ranks))

После запуска функции recursive_feature_elimination(), получаем следующий результат:

{'Qualifications': 1.0, 'Work Type': 1.0, 'Preference': 1.0, 'Job Portal': 1.0, 'Min Experience': 1.0, "'Casual Dress Code, Social and Recreational Activities, Employee Referral Programs, Health and Wellness Facilities, Life and Disability Insurance'": 1.0, "'Childcare Assistance, Paid Time Off (PTO), Relocation Assistance, Flexible Work Arrangements, Professional Development'": 1.0, "'Employee Assistance Programs (EAP), Tuition Reimbursement, Profit-Sharing, Transportation Benefits, Parental Leave'": 1.0, "'Employee Referral Programs, Financial Counseling, Health and Wellness Facilities, Casual Dress Code, Flexible Spending Accounts (FSAs)'": 1.0, "'Flexible Spending Accounts (FSAs), Relocation Assistance, Legal Assistance, Employee Recognition Programs, Financial Counseling'": 1.0, "'Health Insurance, Retirement Plans, Flexible Work Arrangements, Employee Assistance Programs (EAP), Bonuses and Incentive Programs'": 1.0, "'Health Insurance, Retirement Plans, Paid Time Off (PTO), Flexible Work Arrangements, Employee Assistance Programs (EAP)'": 1.0, "'Legal Assistance, Bonuses and Incentive Programs, Wellness Programs, Employee Discounts, Retirement Plans'": 1.0, "'Life and Disability Insurance, Stock Options or Equity Grants, Employee Recognition Programs, Health Insurance, Social and Recreational Activities'": 1.0, "'Transportation Benefits, Professional Development, Bonuses and Incentive Programs, Profit-Sharing, Employee Discounts'": 1.0, "'Tuition Reimbursement, Stock Options or Equity Grants, Parental Leave, Wellness Programs, Childcare Assistance'": 1.0, 'month': 0.5, 'year': 0.33, 'Max Experience': 0.25, 'State': 0.2, 'day': 0.17, 'Sector': 0.14, 'Company': 0.12, 'Ticker': 0.11, 'Job Title': 0.1, 'Role': 0.09, 'Industry': 0.08, 'City': 0.08, 'skills': 0.07, 'Min Salary': 0.07, 'Company Size': 0.06, 'Max Salary': 0.06}

Как можно заметить, наиболее важными параметрами являются 'Qualifications': 1.0, 'Work Type': 1.0, 'Preference': 1.0, 'Job Portal': 1.0, 'Min Experience': 1.0 и все показатели льгот.

Оценка количества кластеров

Для оценки количества кластеров воспользуемся методом локтя - графический метод для оценки оптимального количества кластеров при использовании алгоритма k-means. Данный метод основан на расчете суммы квадратов расстояний между каждым объектом данных и центроидом его кластера. Эта сумма называется инерцией. Чем меньше инерция, тем лучше кластеризация.

Сначала создаем копию данных df, после чего удаляем ненужных столбцов из df с помощью метода drop(). Затем данные разделяем на обучающую и тестовую выборки с помощью функции train_test_split(). Далее инициализируем пустой список inertias, который будет хранить значения инерции для различного количества кластеров. В цикле for перебираем значения k от 1 до 14. Внутри цикла создаем объект KMeans с параметром n_clusters=k, который выполняет кластеризацию обучающей выборки. Значение инерции для текущего количества кластеров добавляется в список inertias. После завершения цикла строим график метода локтя, где по оси x отображается количество кластеров, а по оси y - значение инерции.

С помощью графика выберем точку, где изменение инерции становится менее значительным по сравнению с предыдущими значениями.

df = data.copy()
    df.drop(['Country', 'location', 'Company Size', 'Job Title', 'Role',
             'skills', 'Company', 'Max Experience', 'Min Salary',
             'Max Salary', 'Sector', 'Industry', 'City', 'State', 'Ticker', 'year', 'month', 'day'           
             ],
            axis=1, inplace=True)
    X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.2)
    inertias = []
    for k in range(1, 15):
        kmeans = KMeans(n_clusters=k, random_state=1).fit(X_train.values, y_train.values)
        inertias.append(np.sqrt(kmeans.inertia_))
    plt.plot(range(1, 15), inertias, marker='o')
    plt.xlabel('Number of clusters')
    plt.ylabel('Inertia')
    plt.title("Метод локтя")
    plt.savefig('static/charts/ElbowMethod.png')
    plt.close()

Выполним построение графика:

График "Метод локтя"

Таким образом, с помощью метода локтя получилось визуально определить оптимальное количество кластеров для алгоритма k-means на основе значения инерции, равное 9.

Алгоритм кластеризации K-means

Для работы с алгоритмом кластеризации K-means создадим функцию k_means() . Сохраняем копию оригинальных данных в переменной df. Затем, из этой копии удаляем столбцы, которые имеют наименьшую важность. Далее, данные разделяем на обучающую и тестовую выборки с помощью функции train_test_split. Обучающие данные сохраняются в переменные X_train и y_train, а тестовые данные - в переменные X_test и y_test. Здесь y представляет собой целевую переменную. Затем, создаем объект kmeans класса KMeans с параметром n_clusters=9, что означает, что алгоритм будет искать 9 кластеров в данных. Обучение модели выполняется с помощью метода fit, передавая в него значения X_train и y_train.Далее, применяется обученная модель к тестовым данным с помощью метода predict, чтобы получить метки кластеров. Координаты центроидов кластеров сохраняются в переменной centroids.

def k_means():
    df = data.copy()
    df.drop(['Country', 'location', 'Company Size', 'Preference', 'Job Title', 'Role', 'Job Portal',
             'skills', 'Company', 'Min Experience', 'Max Experience', 'Min Salary',
             'Max Salary', 'Sector', 'Industry', 'City', 'State', 'Ticker', 'year', 'month', 'day',
             "'Casual Dress Code, Social and Recreational Activities, Employee Referral Programs, Health and Wellness Facilities, Life and Disability Insurance'",
             "'Childcare Assistance, Paid Time Off (PTO), Relocation Assistance, Flexible Work Arrangements, Professional Development'",
             "'Employee Assistance Programs (EAP), Tuition Reimbursement, Profit-Sharing, Transportation Benefits, Parental Leave'",
             "'Employee Referral Programs, Financial Counseling, Health and Wellness Facilities, Casual Dress Code, Flexible Spending Accounts (FSAs)'",
             "'Flexible Spending Accounts (FSAs), Relocation Assistance, Legal Assistance, Employee Recognition Programs, Financial Counseling'",
             "'Health Insurance, Retirement Plans, Flexible Work Arrangements, Employee Assistance Programs (EAP), Bonuses and Incentive Programs'",
             "'Health Insurance, Retirement Plans, Paid Time Off (PTO), Flexible Work Arrangements, Employee Assistance Programs (EAP)'",
             "'Legal Assistance, Bonuses and Incentive Programs, Wellness Programs, Employee Discounts, Retirement Plans'",
             "'Life and Disability Insurance, Stock Options or Equity Grants, Employee Recognition Programs, Health Insurance, Social and Recreational Activities'",
             "'Transportation Benefits, Professional Development, Bonuses and Incentive Programs, Profit-Sharing, Employee Discounts'",
             "'Tuition Reimbursement, Stock Options or Equity Grants, Parental Leave, Wellness Programs, Childcare Assistance'"],
            axis=1, inplace=True)
    X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.2)
    kmeans = KMeans(n_clusters=9)
    kmeans.fit(X_train.values, y_train.values)
    labels = kmeans.predict(X_test.values)
    centroids = kmeans.cluster_centers_
    print("Метки кластеров:", labels)
    print("Координаты центроидов:", centroids)
    plt.scatter(X_test['Qualifications'], X_test['Work Type'], c=labels, cmap='viridis')
    plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', color='red')
    plt.xlabel('Qualifications')
    plt.ylabel('Work Type')
    plt.title('KMeans Clustering')
    plt.savefig('static/charts/KMeansClustering.png')
    plt.close()

    print("Уникальных Work Type :", data['Work Type'].nunique())
    print("Уникальных Qualifications:", data['Qualifications'].nunique())

    unique_labels = np.unique(labels)
    for label in unique_labels:
        indices = np.where(labels == label)
        y_values = data_orig.loc[indices, 'Country']
        print(f"Значения y для кластера {label}: {y_values}")

Выполним построение графика:

График "Алгоритм кластеризации K-means"

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

Значения y для кластера 0: 9         Antigua and Barbuda
16                 San Marino
21                     Tuvalu
22                    Eritrea
35              New Caledonia
                 ...         
319899                  Nepal
319912             Uzbekistan
319927               Colombia
319933                  Spain
319955                  Niger
Name: Country, Length: 25672, dtype: object
Значения y для кластера 1: 10                             Bahrain
14                Syrian Arab Republic
19        Democratic Republic Of Congo
31                               Chile
40                       Cote d'Ivoire
                      ...             
319904                      Mauritania
319905                Macao SAR, China
319906                         Vietnam
319929                French Polynesia
319945                       Mauritius
Name: Country, Length: 31971, dtype: object
Значения y для кластера 2: 7          Sao Tome and Principe
15                         Yemen
17              French Polynesia
20                    Azerbaijan
24        British Virgin Islands
                   ...          
319935        Dominican Republic
319937                     Japan
319938                    Gambia
319946                 Indonesia
319949                    Latvia
Name: Country, Length: 38400, dtype: object
Значения y для кластера 3: 0                       Isle of Man
6                    Cayman Islands
11                          Bermuda
23                         Honduras
30                           Jordan
                    ...            
319931    Sint Maarten (Dutch part)
319942         Hong Kong SAR, China
319943                   Bangladesh
319950                      Croatia
319952         Syrian Arab Republic
Name: Country, Length: 51148, dtype: object
Значения y для кластера 4: 3               Benin
4               Chile
5             Belgium
12            Jamaica
18        North Korea
             ...     
319922          Gabon
319925    Korea, Rep.
319926       Ethiopia
319941       Zimbabwe
319951    Korea, Rep.
Name: Country, Length: 38574, dtype: object
Значения y для кластера 5: 1                  Turkmenistan
38              Solomon Islands
42        Virgin Islands (U.S.)
47                       Belize
59            Republic Of Congo
                  ...          
319918                    Spain
319924                 Paraguay
319947                   Brazil
319948         Macao SAR, China
319953                    China
Name: Country, Length: 38422, dtype: object
Значения y для кластера 6: 37               West Bank and Gaza
57                             Guam
102                            Fiji
111                         Ecuador
124                      Cabo Verde
                    ...            
319896    Sint Maarten (Dutch part)
319903                   Madagascar
319914                 South Africa
319940                  Netherlands
319954                      Albania
Name: Country, Length: 25701, dtype: object
Значения y для кластера 7: 2                 Macao SAR, China
8                         Maldives
13                          Gambia
25                            Cuba
27                          Gambia
                    ...           
319892    Turks and Caicos Islands
319920                  Luxembourg
319923         Trinidad and Tobago
319939                       China
319944                        Fiji
Name: Country, Length: 38449, dtype: object
Значения y для кластера 8: 48                      Malta
49                     Panama
52          Republic Of Congo
81                 Bangladesh
82                      Nepal
                 ...         
319902               Cambodia
319921               Barbados
319932                Lesotho
319934    St. Kitts and Nevis
319936                Nigeria
Name: Country, Length: 31619, dtype: object

Также выведем координаты центроидов:

Координаты центроидов: [[2.49909662 0.4986962 ]
 [6.49757212 3.00005221]
 [1.12332665 3.12941867]
 [6.79715885 0.40238426]
 [3.99726263 3.50030885]
 [8.50117367 3.49953735]
 [4.2877207  1.14426123]
 [8.60271303 1.19776253]
 [0.40101301 0.79759215]]

И оценим качество кластеризации, используя силуэтный коэффициент и индекс Дэвиса-Болдина:

  1. Силуэтный коэффициент - это метрика, которая измеряет, насколько точка хорошо соответствует своему собственному кластеру в сравнении с другими кластерами. Он находится в диапазоне от -1 до 1, где значение ближе к 1 указывает на хорошую кластеризацию, а значение ближе к -1 указывает на плохую кластеризацию.
    # Оценка силуэтного коэффициента
    silhouette = silhouette_score(X_test.values, kmeans.predict(X_test.values))
    print("Силуэтный коэффициент:", silhouette)

В нашем случае силуэтный коэффициент равен 0.4086103390706535. 2. Индекс Дэвиса-Болдина - это метрика, которая измеряет сходство между кластерами на основе их средних расстояний и средних расстояний между кластерами. Чем меньше значение этого индекса, тем лучше кластеризация.

    # Оценка индекса Дэвиса-Болдина
    davies_bouldin = davies_bouldin_score(X_test.values, kmeans.predict(X_test.values))
    print("Индекс Дэвиса-Болдина:", davies_bouldin)

В нашем случае индекс Дэвиса-Болдина равен 0.8682047121172671.

Вывод

Таким образом, с помощью оценок силуэтного коэффициента и индекса Дэвиса-Болдина, можно сделать следующие выводы о качестве кластеризации:

  1. Силуэтный коэффициент равен 0.4086103390706535. В данном случае, значение силуэтного коэффициента выше 0, что говорит о том, что кластеры имеют некоторую степень разделения, но не являются идеально разделимыми. В целом, это может указывать на некоторое качество кластеризации, но не является оптимальным.
  2. Индекс Дэвиса-Болдина равен 0.8682047121172671. Значение этого индекса является положительным числом. В данном случае, значение индекса Дэвиса-Болдина выше 0, что указывает на некоторое сходство между кластерами.

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