Код Python для реализации AHP: пример лидеров

В этой статье:

  • Поделюсь практической реализацией AHP на Python,
  • Я не буду подробно объяснять теорию AHP,
  • Будем реализовывать пример из Википедии,
  • Я поделюсь с вами полным кодом.

Вотпример лидера из Википедии.

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

Приступаем к реализации.

Импортировать необходимые библиотеки:

import numpy as np
import pandas as pd
from sklearn.preprocessing import normalize

Реализуйте основной метод:

(Если вас не интересуют подробности этого метода, перейдите к следующему разделу: Начать выбор.)

Самая важная часть нашего кода Python — это наш основной метод: compute_priorities.

Этот метод выполняет базовые расчеты AHP. Он получает общий балл и список функций и распределяет этот общий балл по функциям. Таким образом, приоритеты вычисляются и возвращаются в виде словаря.

Первый ввод: функции (2-й список)

Этот 2d список имеет 2 строки. Первая строка содержит имена функций, тогда как вторая строка содержит шкалы AHP по сравнению с первой функцией.

Пример ввода: [['A','B','C','D'], [2,5,6]]

Вторая строка содержит n-1 (имеется n признаков) количество целых чисел от 1 до 9, которые находятся в шкале AHP.

В примере А является наиболее важной функцией.

Второй ввод: total_point (целое число)

По заданным баллам AHP рассчитываются веса. Затем в соответствии с весами распределяются общие баллы для определения приоритетов.

Общее количество очков равно 1 или 100 в начале дерева AHP.

Вывод словаря:

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

Важные примечания к методу:

  • Первая функция входного списка должна быть одной из самых важных функций.
  • Каждая функция сравнивается только с первой функцией.

Код Python:

def calculate_priorities(features, total_point):
    
    # There are n features, so an n*n 'ones' matrix is composed.
    # The elements on the diagonal are all one.
    n = len(features[0])
    ahp_matrix = np.ones([n,n])
    
    # The matrix is filled according to ahp calculations.
    for i in range(0,n):
        for j in range(0,n):
            # The element (j,i) equals 1/(i,j)
            if i<j:
                if i==0:
                    # The first row is the second row of the input list. 
                    ahp_matrix[i,j] = float(features[1][j-1])
                    # Then, the first column is filled.
                    ahp_matrix[j,i] = 1/float(ahp_matrix[i,j])
                else:
                    # The rest of the cells are filled according to firs row.
                    if ahp_matrix[0,j]>ahp_matrix[0,i]:
                        ahp_matrix[i,j] = ahp_matrix[0,j]-ahp_matrix[0,i]+1
                    else:
                        ahp_matrix[i,j] = 1/((ahp_matrix[0,i]-ahp_matrix[0,j])+1)
                    ahp_matrix[j,i] = 1/float(ahp_matrix[i,j])
    
    # The matrix is normalized according to axis 0
    normed_matrix = normalize(ahp_matrix, axis=0, norm='l1')
    
    # Weights are calculated
    weights = normed_matrix.mean(1)
    # The total point is distributed according to weights
    
    points = total_point*weights
    # Feature names and points are stored in a dataframe
    
    return dict(zip(features[0],points))

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

Начать выбор

На первом уровне дерева будем сравнивать критерии друг с другом.

На изображении вы видите сравнение критериев по шкалам AHP. В этом образе есть некоторое несоответствие.

Например, в первом ряду Образование равно 4, а Обаяние равно 3. Итак, когда мы сравниваем их друг с другом, должно быть 2, но вы видите, что в третьей строке 3.

Мы будем реализовывать наш код с наименьшим несоответствием, и поэтому мы будем использовать только строку, не содержащую дробей. В данном случае это первый ряд: 1, 4, 3, 7. Опыт — самый важный.

critetia = [['Experience','Education','Charisma','Age'],[4,3,7]]
total_point = 1
main_dict = calculate_priorities(critetia, total_point)
main_dict

Результаты немного отличаются от Википедии из-за проблемы несоответствия.

Теперь мы распределим эти очки между тремя лидерами.

Начнем с опыта.

Поскольку строки несовместимы, мы будем использовать строку, не содержащую дробей. На этот раз это второй ряд: 4, 1, 9. У Дика больше всего опыта, поэтому он будет в начале списка.

experience_feature = [['Dict','Tom','Harry'],[4,9]]
experience_dict = calculate_priorities(experience_feature, main_dict['Experience'])
experience_dict

Результаты отличаются по 2 причинам:

  • Мы реализуем с наименьшим несоответствием.
  • Мы распределили общее количество очков опыта, тогда как Википедия распределила 1. (Википедия позже умножает очки опыта на эти результаты.)

Настало время сравнить уровень образования лидеров.

Мы используем третью строку в качестве уровней приоритета: 5, 7, 1. На этот раз у Гарри самый высокий приоритет. (Значит, он в начале списка.)

education_feature = [['Harry','Tom','Dict'],[5,7]]
education_dict = calculate_priorities(education_feature, main_dict['Education'])
education_dict

Результат причины отличается от причины, указанной выше. В итоге вы увидите, что разница в результатах очень мала.

Пришло время сравнить харизму.

Мы будем использовать первую строку, и на этот раз Том впереди: 1, 5, 9.

charisma_feature = [['Tom','Dict','Harry'],[5,9]]
charisma_dict = calculate_priorities(charisma_feature, main_dict['Charisma'])
charisma_dict

Остался только возраст.

На этот раз второй ряд. Дик впереди.

age_feature = [['Dict','Tom','Harry'],[3,9]]
age_dict = calculate_priorities(age_feature, main_dict['Age'])
age_dict

Соберем всех вместе.

df = pd.DataFrame([experience_dict, education_dict, charisma_dict, age_dict])
df.index = main_dict.keys()
df

Итак, мы получили приоритеты для 4 фич и 3 лидеров. Теперь мы можем суммировать результаты, чтобы получить общее количество баллов.

total = df.sum()
total.name = 'Total'
df = pd.concat([df,total.to_frame().T])
df

Дикт - победитель отбора, и Том следует за ним. Ниже приведены результаты из Википедии.

Том получил 0,358 в Википедии, а мы дали 0,359, тогда как Dict получил 0,492 из Википедии, а мы дали 0,478.

Причина, как я уже сказал, несоответствие в Википедии.

Это все, что касается реализации AHP в Python. Вот полный код.

import numpy as np
import pandas as pd
from sklearn.preprocessing import normalize

def calculate_priorities(features, total_point):
    
    # There are n features, so an n*n 'ones' matrix is composed.
    # The elements on the diagonal are all one.
    n = len(features[0])
    ahp_matrix = np.ones([n,n])
    
    # The matrix is filled according to ahp calculations.
    for i in range(0,n):
        for j in range(0,n):
            # The element (j,i) equals 1/(i,j)
            if i<j:
                if i==0:
                    # The first row is the second row of the input list. 
                    ahp_matrix[i,j] = float(features[1][j-1])
                    # Then, the first column is filled.
                    ahp_matrix[j,i] = 1/float(ahp_matrix[i,j])
                else:
                    # The rest of the cells are filled according to firs row.
                    if ahp_matrix[0,j]>ahp_matrix[0,i]:
                        ahp_matrix[i,j] = ahp_matrix[0,j]-ahp_matrix[0,i]+1
                    else:
                        ahp_matrix[i,j] = 1/((ahp_matrix[0,i]-ahp_matrix[0,j])+1)
                    ahp_matrix[j,i] = 1/float(ahp_matrix[i,j])
    
    # The matrix is normalized according to axis 0
    normed_matrix = normalize(ahp_matrix, axis=0, norm='l1')
    
    # Weights are calculated
    weights = normed_matrix.mean(1)
    # The total point is distributed according to weights
    
    points = total_point*weights
    # Feature names and points are stored in a dataframe
    
    return dict(zip(features[0],points))

critetia = [['Experience','Education','Charisma','Age'],[4,3,7]]
total_point = 1
main_dict = calculate_priorities(critetia, total_point)

experience_feature = [['Dict','Tom','Harry'],[4,9]]
experience_dict = calculate_priorities(experience_feature, main_dict['Experience'])

education_feature = [['Harry','Tom','Dict'],[5,7]]
education_dict = calculate_priorities(education_feature, main_dict['Education'])

charisma_feature = [['Tom','Dict','Harry'],[5,9]]
charisma_dict = calculate_priorities(charisma_feature, main_dict['Charisma'])

age_feature = [['Dict','Tom','Harry'],[3,9]]
age_dict = calculate_priorities(age_feature, main_dict['Age'])

df = pd.DataFrame([experience_dict, education_dict, charisma_dict, age_dict])
df.index = main_dict.keys()
total = df.sum()
total.name = 'Total'
df = pd.concat([df,total.to_frame().T])
df

Надеюсь, вам понравится и принесет пользу.

Подпишитесь на мою ленту. (Получите мои истории в свой почтовый ящик.)

Стать участником и (или просто) обратиться ко мне. (Поддержите меня своим членским взносом.)

Подпишитесь на DDIntel Здесь.

Посетите наш сайт здесь: https://www.datadriveninvestor.com

Примените код: DDI2022, чтобы получить СКИДКУ 30% на РАСПРОДАЖУ в Черную пятницу.