-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathund_DEA.py
More file actions
160 lines (140 loc) · 5.21 KB
/
Copy pathund_DEA.py
File metadata and controls
160 lines (140 loc) · 5.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import numpy as np
import os
import pandas as pd
import pickle
import pulp
class DEAProblem:
def __init__(
self,
inputs,
outputs,
bad_outs,
weight_vector,
directional_factor=None,
returns="CRS",
disp = 'weak disposability',
in_weights=[0, None],
out_weights=[0, None],
badout_weights=[0, None],
):
self.inputs = inputs
self.outputs = outputs
self.bad_outs = bad_outs
self.returns = returns
self.weight_vector = (
weight_vector # weight vector in directional distance function
)
self.disp = disp
self.J, self.I = self.inputs.shape # no of DMUs, inputs
_, self.R = self.outputs.shape # no of outputs
_, self.S = self.bad_outs.shape # no of bad outputs
self._i = range(self.I) # inputs
self._r = range(self.R) # outputs
self._s = range(self.S) # bad_output
self._j = range(self.J) # DMUs
if directional_factor == None:
self.gx = self.inputs
self.gy = self.outputs
self.gb = self.bad_outs
else:
self.gx = directional_factor[: self.I]
self.gy = directional_factor[self.I : (self.I + self.J)]
self.gy = directional_factor[(self.I + self.J) :]
self._in_weights = in_weights # input weight restrictions
self._out_weights = out_weights # output weight restrictions
self._badout_weights = badout_weights # bad output weight restrictions
# creates dictionary of pulp.LpProblem objects for the DMUs
self.dmus = self._create_problems()
def _create_problems(self):
"""
Iterate over the DMU and create a dictionary of LP problems, one
for each DMU.
"""
dmu_dict = {}
for j0 in self._j:
dmu_dict[j0] = self._make_problem(j0)
return dmu_dict
def _make_problem(self, j0):
"""
Create a pulp.LpProblem for a DMU.
"""
# Set up pulp
prob = pulp.LpProblem("".join(["DMU_", str(j0)]), pulp.LpMaximize)
self.weights = pulp.LpVariable.dicts(
"Weight", (self._j), lowBound=self._in_weights[0]
)
self.betax = pulp.LpVariable.dicts(
"scalingFactor_x", (self._i), lowBound=0, upBound=1
)
self.betay = pulp.LpVariable.dicts("scalingFactor_y", (self._r), lowBound=0)
self.betab = pulp.LpVariable.dicts(
"scalingFactor_b", (self._s), lowBound=0, upBound=1
)
# Set returns to scale
if self.returns == "VRS":
prob += pulp.lpSum([self.weights[j] for j in self.weights]) == 1
# Set up objective function
prob += pulp.lpSum(
[(self.weight_vector[i] * self.betax[i]) for i in self._i]
+ [(self.weight_vector[self.I + r] * self.betay[r]) for r in self._r]
+ [
(self.weight_vector[self.I + self.R + s] * self.betab[s])
for s in self._s
]
)
# Set up constraints
for i in self._i:
prob += (
pulp.lpSum(
[(self.weights[j0] * self.inputs.values[j0][i]) for j0 in self._j]
)
<= self.inputs.values[j0][i] - self.betax[i] * self.gx.values[j0][i]
)
for r in self._r:
prob += (
pulp.lpSum(
[(self.weights[j0] * self.outputs.values[j0][r]) for j0 in self._j]
)
>= self.outputs.values[j0][r] + self.betay[r] * self.gy.values[j0][r]
)
if self.disp == "weak disposability":
for s in self._s: # weak disposability
prob += (
pulp.lpSum(
[
(self.weights[j0] * self.bad_outs.values[j0][s])
for j0 in self._j
]
)
== self.bad_outs.values[j0][s]
- self.betab[s] * self.gb.values[j0][s]
)
elif self.disp == "strong disposability":
for s in self._s: # strong disposability
prob += (
pulp.lpSum(
[
(self.weights[j0] * self.bad_outs.values[j0][s])
for j0 in self._j
]
)
>= self.bad_outs.values[j0][s]
- self.betab[s] * self.gb.values[j0][s]
)
return prob
def solve(self):
"""
Iterate over the dictionary of DMUs' problems, solve them, and collate
the results into a pandas dataframe.
"""
sol_status = {}
sol_weights = {}
sol_efficiency = {}
for ind, problem in list(self.dmus.items()):
problem.solve()
sol_status[ind] = pulp.LpStatus[problem.status]
sol_weights[ind] = {}
for v in problem.variables():
sol_weights[ind][v.name] = v.varValue
sol_efficiency[ind] = pulp.value(problem.objective)
return sol_status, sol_efficiency, sol_weights