簡體   English   中英

找到矩陣中的最大值以最大化分數

[英]Find the highest value in the Matrix to maximize the score

題:

我想在每個老師和每個小組的矩陣中找到最高值,以最大化哪個小組應該與哪個老師一起去的比例。

            Teacher A   Teacher B   Teacher C   Teacher D
Group 1     50          40          20           50
Group 2     30          10          40          100
Group 3     80          60          40           20

在上表中。 我知道如何找出行和列中的最高值,但我想在教師和組的組合中找到最高值,即教師不能屬於兩個組,而組不能屬於兩個教師。 是的,可以有比小組更多的教師。

所以我正在尋找最終的輸出如下:

解決方案

Group 1 with Teacher B: 40
Group 2 with Teacher D: 100
Group 3 with Teacher A: 80

到目前為止,我的工作已經嘗試了幾種使用Pandas解決這個問題的方法,但一切都只獲取行和列的最高值,或者充其量是最高的鍵的名稱。 我在這里學習了教程但沒有取得太大的成功。 任何指導都會很棒。

首先搜索所有可能的排列,然后取最大值作為值的總和,最后打印它。 這是我使用數據框的實現:

import itertools
m = [
    [50, 40, 20, 50],
    [30, 10, 40, 100],
    [80, 60, 40, 20]
]
rows = ['Group 1', 'Group 2', 'Group 3']
cols = ['Teacher A', 'Teacher B', 'Teacher C', 'Teacher D']
df = pd.DataFrame(m, index=rows, columns=cols)

permuts = itertools.permutations(cols, len(rows))

L = []
for p in permuts:
    s = 0
    d = {}
    for i, r in enumerate(rows):
        s += df[p[i]][r]
        d[r] = p[i]
    obj = [s, d]
    L.append(obj)

result = max(L, key=lambda x: x[0])
# [220, {'Group 1': 'Teacher B', 'Group 2': 'Teacher D', 'Group 3': 'Teacher A'}]
# Here 220 is the maximum sum you can have

result_dict = result[1]
# {'Group 1': 'Teacher B', 'Group 2': 'Teacher D', 'Group 3': 'Teacher A'}

for i, v in result_dict.items():
    print("{} with {} : {}".format(i, v, df[v][i]))

# Group 1 with Teacher B : 40
# Group 2 with Teacher D : 100
# Group 3 with Teacher A : 80

說明

這是itertools.permutations如何工作的一個小例子。 數字2是每個排列的長度, ['a','b','c']是排列的元素:

import itertools
permuts = itertools.permutations(['a','b','c'],2)
for i in a:
    print(i)

輸出:(這里有 6 個排列)

('a', 'b')
('a', 'c')
('b', 'a')
('b', 'c')
('c', 'a')
('c', 'b')

在我們的例子中,我們有 3 個小組,所以我們需要 4 個可用的教師中的 3 個(教師 A、B、C 和 D)。 例如排列('Teacher A', 'Teacher B', 'Teacher C')表示Group1=Teacher A, Group2=Teacher B, Group3=Teacher C)

因此,我們將使用permuts = itertools.permutations(cols, len(rows))枚舉 3 位教師的所有有序排列:

('Teacher A', 'Teacher B', 'Teacher C')
('Teacher A', 'Teacher B', 'Teacher D')
('Teacher A', 'Teacher C', 'Teacher B')
...
('Teacher D', 'Teacher C', 'Teacher A')
('Teacher D', 'Teacher C', 'Teacher B')

所以在我們的變量permuts得到 24 個元組

然后我們計算每個排列的值的總和,我們得到一個包含這些元素的大列表:

L = []
for p in permuts:
    s = 0
    d = {}
    for i, r in enumerate(rows):
        s += df[p[i]][r]
        d[r] = p[i]
    obj = [s, d]
    L.append(obj)

輸出 L:

[
    [100, {'Group 1': 'Teacher A', 'Group 2': 'Teacher B', 'Group 3': 'Teacher C'}]
    [80, {'Group 1': 'Teacher A', 'Group 2': 'Teacher B', 'Group 3': 'Teacher D'}]
...
    [220, {'Group 1': 'Teacher B', 'Group 2': 'Teacher D', 'Group 3': 'Teacher A'}]
]
...

第一個數字(例如 100、80 和 220)表示此特定排列的值的總和。

然后我們選擇總和最大的排列,這里是220

result = max(L, key=lambda x: x[0])
# [220, {'Group 1': 'Teacher B', 'Group 2': 'Teacher D', 'Group 3': 'Teacher A'}]

最后,我們使用print("{} with {} : {}".format(i, v, df[v][i]))數據幀中的值的排列。 例如df["Teacher B"]["Group 1"] = 40

Group 1 with Teacher B : 40
Group 2 with Teacher D : 100
Group 3 with Teacher A : 80

這看起來像一個優化問題。

您有 2 種方法來處理它(從理論上講)。

  1. 啟發式:

    除了病理用例,我們可以認為矩陣中的最高值將在最終結果中結束。 這里我們有 100 個用於 Group2 和教師 D。然后我們移除 Group 2 的行和教師 D 的列並進行迭代。

    這一步一步給出:

     Group 2 Teacher D 100 Group 3 Teacher A 80 Group 1 Teacher B 50
  2. 詳盡無遺

    前面的方法會導致正確的結果是值有很大的差異,但如果值彼此太接近,則只能找到接近最大值的解決方案。 窮舉方法包括計算每個可能組合的值的總和並保持最高值。 它當然會給出相同的結果,但是我需要太多的操作才能在這里手動顯示它......

Python 翻譯

第一種方法是迭代但很簡單:

# heuristic

dfA = df
result = {}

while (len(dfA) > 0):
    mx = dfA.max()     # find max per teacher
    mmx = pd.Series(mx[mx == mx.max()])  # find absolute max of matrix
    teacher = mmx.index[0]                       # get teacher
    val = mmx.values[0]                          # get value
    group = dfA[dfA[teacher] == val].index[0]    # get group
    result[group] = (teacher, val)               # store the triplet
    dfA = dfA.drop(index = group).drop(columns = teacher) # remove the row and column

dfout = pd.DataFrame(result).T
print(dfout.to_string())

按預期提供:

                 0    1
Group 2  Teacher D  100
Group 3  Teacher A   80
Group 1  Teacher B   40

第二種方法更具確定性,但可能無法擴展到大型數據集:

import itertools

# compute with itertools all the possible permutations of group-teachers
mindex = pd.MultiIndex.from_tuples(itertools.permutations(df.columns, len(df)))

# compute the total value for each permutation
total = pd.DataFrame(data = 0, columns=mindex, index=df.index
                     ).transform(lambda x: pd.Series(
                         [df.loc[x.index[i], x.name[i]]
                          for i in range(len(x))], index=x.index)).sum()

# prepare the resulting dataframe
dfout = pd.DataFrame({'Groups': df.index,
                      'Teachers': total[total == total.max()].index[0]})

# extract the value per group
dfout['val'] = dfout.apply(lambda x: df.loc[x['Groups'], x['Teachers']], axis=1)

print(dfout.to_string())

它提供與預期相同的值

    Groups   Teachers  val
0  Group 1  Teacher B   40
1  Group 2  Teacher D  100
2  Group 3  Teacher A   80

計算行和列的最佳組合以優化轉換。 我使用了使用匈牙利算法的linear_sum_assignment包。 更多可以在這里找到

from scipy.optimize import linear_sum_assignment
import pandas as pd

df = pd.read_csv("myfile.csv", index_col=0)
gain = df.to_numpy()
row_ind, col_ind = linear_sum_assignment(gain, maximize=True)
print(row_ind)
print(col_ind)
print(gain[row_ind, col_ind].sum())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM