画像のようなCSVファイルを読み取り、ハンガリアン法(https://qiita.com/masa0599/items/47491e2e4ddb8e45f4eb)を行いたいのですが,Python初心者なため教えていただけないでしょうか.
その時,距離の総和の最小と最大それぞれの場合の
支援者と高齢者のいる住宅番号の組み合わせ,距離がわかるようにしたいです.
URLにハンガリアン法のコードはあります。
↓画像の補足
1行目に支援者がいる住宅番号,A列に高齢者がいる住宅番号を記載しております.A列に1が2つあるのは,高齢者が住宅番号1に2人存在するためです.
つまり,支援者は1~5の住宅に1人ずつというような感じです.
B2-F5は距離です
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答6件
0
ベストアンサー
1.以下のスクリプトを作成し、Wariate.py という名で保存してください。
python3
1import csv 2import sys 3from munkres import Munkres 4import numpy as np 5import copy 6 7def pout(mtx,ansMtx1,ansMtx2): 8 arrs = [] 9 for idx1,idx2 in zip(ansMtx1,ansMtx2): 10 arr = [] 11 arr.append(idx1[0]) 12 arr.append(idx1[1]) 13 arr.append(mtx[idx1]) 14 arr.append(idx2[0]) 15 arr.append(idx2[1]) 16 arr.append(mtx[idx2]) 17 arrs.append(arr) 18 return arrs 19 20if len(sys.argv) != 3: 21 print(sys.argv[0],"P1 P2",file=sys.stderr) 22 print("P1:input CSVfile",file=sys.stderr) 23 print("P2:output CSVfile",file=sys.stderr) 24 sys.exit(1) 25 26mtx = np.loadtxt(sys.argv[1],delimiter=',',dtype='int32') 27ansMtx1 = Munkres().compute(copy.copy(mtx)) 28asum1 = sum([mtx[idx] for idx in ansMtx1]) 29 30mtx_max = mtx * (-1) 31ansMtx2 = Munkres().compute(copy.copy(mtx_max)) 32asum2 = sum([mtx[idx] for idx in ansMtx2]) 33 34arrs = pout(mtx,ansMtx1,ansMtx2) 35np.savetxt(sys.argv[2],arrs,fmt='%d',delimiter=',') 36print(f"STATUS=OK Min sum = {asum1} Max sum={asum2}") 37sys.exit(0) 38
2.以下のマクロを標準モジュールに登録してください。
下記のフォルダ名は、私の環境でしけんしたものです。
Const pyscript As String = "D:\goo\python\goo_高齢者支援\Wariate.py"
Const infile As String = "D:\goo\python\goo_高齢者支援\INPUT.csv"
Const outfile As String = "D:\goo\python\goo_高齢者支援\OUTPUT.csv"
あなたの環境にあわせて、適切に設定してください。
3.下記のシートを作成してください。
シート名:高齢者支援
シート名:実行結果
4.マクロを実行すると
高齢者支援に記述されたデータを読み取り、その結果が実行結果に格納されます。
又、高齢者支援に色づけされます。
(最短:緑、最長:黄、最短と最長の両方共有:赤)
実行結果の2行は見出しです。あなたが、予め、作成しておいてください。
VBA
1Option Explicit 2 3Public Sub 高齢者支援() 4 Const pyscript As String = "D:\goo\python\goo_高齢者支援\Wariate.py" 5 Const infile As String = "D:\goo\python\goo_高齢者支援\INPUT.csv" 6 Const outfile As String = "D:\goo\python\goo_高齢者支援\OUTPUT.csv" 7 Dim ws1 As Worksheet 8 Dim ws2 As Worksheet 9 Dim maxrow As Long 10 Dim maxcol As Long 11 Dim wrow As Long 12 Dim wcol As Long 13 Set ws1 = Worksheets("高齢者支援") 14 Set ws2 = Worksheets("実行結果") 15 maxrow = ws1.Cells(rows.Count, 1).End(xlUp).Row 16 maxcol = ws1.Cells(1, Columns.Count).End(xlToLeft).Column 17 If maxrow < 4 Then Exit Sub 18 If maxcol < 4 Then Exit Sub 19 ws1.Range(ws1.Cells(1, 1), ws1.Cells(maxrow, maxcol)).Interior.Pattern = xlNone 20 21 '入力ファイル作成 22 Open infile For Output As #1 23 For wrow = 2 To maxrow 24 Dim oline As String 25 oline = ws1.Cells(wrow, 2).Value 26 For wcol = 3 To maxcol 27 oline = oline & "," & ws1.Cells(wrow, wcol).Value 28 Next 29 Print #1, oline 30 Next 31 Close #1 32 'Python 実行 33 Dim WSH, wExec, sCmd As String, result As String, ResultERR As String 34 Set WSH = CreateObject("WScript.Shell") 35 sCmd = "python " & pyscript & " " & infile & " " & outfile 36 Set wExec = WSH.Exec("%ComSpec% /c " & sCmd) 37 Do While wExec.Status = 0 38 DoEvents 39 Loop 40 result = wExec.StdOut.ReadAll 41 If result <> "" Then 42 MsgBox result 43 Else 44 MsgBox ("スクリプト実行エラー") 45 ResultERR = wExec.StdErr.ReadAll 46 MsgBox (ResultERR) 47 Exit Sub 48 End If 49 '実行結果設定 50 Call set_result(ws1, ws2, result, outfile) 51 MsgBox ("完了") 52End Sub 53Private Sub set_result(ByVal ws1 As Worksheet, ByVal ws2 As Worksheet, ByVal result As String, ByVal fpath As String) 54 Dim maxrow As Long 55 Dim wrow As Long 56 Dim sline As String 57 Dim elm As Variant 58 Dim row1 As Long 59 Dim col1 As Long 60 Dim minsum As Long: minsum = 0 61 Dim maxsum As Long: maxsum = 0 62 If result = "" Then Exit Sub 63 If Left(result, 9) <> "STATUS=OK" Then Exit Sub 64 Set ws2 = Worksheets("実行結果") 65 maxrow = ws2.Cells(rows.Count, "A").End(xlUp).Row 66 If maxrow > 2 Then 67 ws2.Range("A3:J" & maxrow).ClearContents 68 End If 69 Open fpath For Input As #2 70 wrow = 3 71 Do Until EOF(2) 72 Line Input #2, sline 73 elm = Split(sline, ",") 74 row1 = elm(0) + 2 75 col1 = elm(1) + 2 76 ws1.Cells(row1, col1).Interior.Color = 5296274 '緑 77 ws2.Cells(wrow, "A").Value = ws1.Cells(row1, 1).Value 78 ws2.Cells(wrow, "B").Value = ws1.Cells(1, col1).Value 79 ws2.Cells(wrow, "C").Value = elm(0) 80 ws2.Cells(wrow, "D").Value = elm(1) 81 ws2.Cells(wrow, "E").Value = elm(2) 82 row1 = elm(3) + 2 83 col1 = elm(4) + 2 84 If ws1.Cells(row1, col1).Interior.Color <> 5296274 Then 85 '未設定なら黄 86 ws1.Cells(row1, col1).Interior.Color = 65535 87 Else 88 '緑設定済みなら赤 89 ws1.Cells(row1, col1).Interior.Color = 255 90 End If 91 ws2.Cells(wrow, "F").Value = ws1.Cells(row1, 1).Value 92 ws2.Cells(wrow, "G").Value = ws1.Cells(1, col1).Value 93 ws2.Cells(wrow, "H").Value = elm(3) 94 ws2.Cells(wrow, "I").Value = elm(4) 95 ws2.Cells(wrow, "J").Value = elm(5) 96 minsum = minsum + elm(2) 97 maxsum = maxsum + elm(5) 98 wrow = wrow + 1 99 Loop 100 Close #2 101 ws2.Cells(wrow, "A").Value = "合計" 102 ws2.Cells(wrow, "E").Value = minsum 103 ws2.Cells(wrow, "J").Value = maxsum 104End Sub 105
投稿2023/11/14 05:31
総合スコア5493
0
munkresのインストールが正常に終了し、munkresを使用するスクリプトが正常に動作する前提となりますが、
以下のようにしては、いかがでしょうか。
1.シート名:高齢者支援
に高齢者住宅番号と支援者住宅番号、距離を記入する。
2.マクロを実行すると、
上記シートの距離の箇所をCSVファイルに出力する。(B2:F5の範囲)
3.マクロからpythonを実行し、最短距離と最長距離を算出する。
算出結果を別のCSVファイルへ出力する。
4.マクロは、算出結果が書かれたCSVファイルを読み込み、
シート名:算出結果へ出力する。
同時に、シート名:高齢者支援に最短距離と最長距離を色づけする。
上記で良ければ、マクロとpythonスクリプトを提供可能です。
投稿2023/11/13 10:03
総合スコア5493
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/11/14 01:06
2023/11/14 05:12
0
投稿2023/11/13 05:06
総合スコア5493
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/11/13 05:21
2023/11/13 06:30
2023/11/13 14:00
2023/11/14 00:38 編集
0
URLにハンガリアン法のコードはあります。
とは 割当問題のハンガリアン法をpythonで実装してみた の「python による実装」のコードと解釈しました。これを用いる手順としては以下になります。
-
このコードを
qiita_hungarian.py
という名前のファイルに保存し,カレントディレクトリ(フォルダ)に置きます。 -
このコードは正方行列でないと正解が得られない場合があるようなので,CSV ファイル(
sample.csv
とします)の6行目にダミー行「x,0,0,0,0,0」を追加して,同じディレクトリに置きます。 -
下記の記述例をファイル(例えば
code1.py
)に保存し,同じディレクトリに置きます。そして,実行(例えば> python code1.py
)します。
なお,「最大の割当」を求める際は,与える距離データの符号を負にしてから「最小の割当」を求めました。総当たり法(Brute-force method)の結果とは一致しましたが,(qiita_hungarian.py
のコードの中身をよく理解できていないので)この方法が正しいとまでは言えません。
Python
1import pandas as pd 2from qiita_hungarian import Hungarian 3from itertools import permutations 4 5df = pd.read_csv('sample.csv', index_col=0) 6print(df) 7# 1 2 3 4 5 8# 1 0 10 30 40 50 9# 1 0 10 30 40 50 10# 3 30 15 0 20 25 11# 5 50 35 25 15 0 12# x 0 0 0 0 0 13 14for k in (1, -1): 15 h = Hungarian() 16 result = h.compute(df.to_numpy() * k) 17 distance = sum(df.iloc[t] for t in result) 18 pairing = [(df.index[i], df.columns[j]) for i, j in result 19 if df.index[i] != 'x'] 20 print('min:' if k == 1 else 'max:', distance, pairing) 21# min: 10 [('1', '1'), ('1', '2'), ('3', '3'), ('5', '5')] 22# max: 155 [('1', '4'), ('1', '5'), ('3', '1'), ('5', '2')] 23 24# Brute-force method 25sum_lst = [sum(df.iloc[t] for t in zip(range(5), p)) 26 for p in permutations(range(5))] 27print(f'min: {min(sum_lst)}, max: {max(sum_lst)}') 28# min: 10, max: 155
投稿2023/11/13 04:56
編集2023/11/13 23:38総合スコア410
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/11/13 13:32
2023/11/13 13:52
2023/11/13 15:26
2023/11/13 23:26
2023/11/14 06:35
0
見出しの部分を除いたCSVファイルであることが、前提です。
提示例ではB2:F5
0,10,30,40,50
0,10,30,40,50
30,15,0,20,25
50,35,25,15,0
のようなCSVファイルです。
python3
1import csv 2import sys 3from munkres import Munkres 4import numpy as np 5import copy 6 7arr = [] 8if len(sys.argv) != 2: 9 print(sys.argv[0],"P1") 10 print("P1:CSVファイル名",file=sys.stderr) 11 sys.exit(1) 12fin = open(sys.argv[1], "r") 13work = csv.reader(fin) 14 15for work_l in work: 16 work_n = list(map(lambda x: int(x),work_l)) 17 arr.append(work_n) 18fin.close() 19 20mtx = np.array(arr) 21ansMtx = Munkres().compute(copy.copy(mtx)) 22asum = sum([mtx[idx] for idx in ansMtx]) 23print(mtx) 24print(ansMtx) 25print(f"Minmum sum = {asum}") 26
上記で最小値は求められます。
最大値の求め方は不明です。
Usage:
python.exe スクリプトファイル CSVファイル
投稿2023/11/12 10:36
総合スコア5493
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/11/12 15:24
2023/11/12 22:31
2023/11/13 00:11
2023/11/13 04:05
2023/11/13 04:07
2023/11/13 04:26
2023/11/13 04:34
2023/11/13 04:35
2023/11/13 04:37
2023/11/13 04:41
2023/11/13 04:49
2023/11/13 04:50
2023/11/13 04:54
2023/11/13 05:11 編集
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/11/14 06:05
2023/11/14 06:11
2023/11/14 06:15
2023/11/14 06:18
2023/11/14 06:20
2023/11/14 06:24
2023/11/14 06:35
2023/11/23 04:49
2023/11/23 05:28
2023/11/24 04:56
2023/11/24 05:32
2023/11/24 07:24
2023/11/24 23:37