点赞发Nature 关注中Science
最近在想怎么用python实现非径向距离函数
之前用了pyDEA包https://pypi.org/project/pyDEA/,那个包比较简陋,只有普通的CCR BCC模型。
另一方面,MaxDEA因为是打包好的嘛,所以不够灵活。所以想自己做一个NDDF的模型出来。
所以用pyDEA的初始代码进行了一些改造,直接上代码:
import numpy as np import pandas as pd import pulp class DEAProblem: def __init__(self, inputs, outputs, weight_vector, directional_factor=None, returns='CRS', in_weights=[0, None], out_weights=[0, None]): self.inputs = inputs self.outputs = outputs self.returns = returns self.weight_vector = weight_vector # weight vector in directional distance function self.J, self.I = self.inputs.shape # no of DMUs, inputs _, self.R = self.outputs.shape # no of outputs self._i = range(self.I) # inputs self._r = range(self.R) # outputs self._j = range(self.J) # DMUs if directional_factor == None: self.gx = self.inputs self.gy = self.outputs else: self.gx = directional_factor[:self.I] self.gy = directional_factor[-self.J:] self._in_weights = in_weights # input weight restrictions self._out_weights = out_weights # 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) self.betay = pulp.LpVariable.dicts("scalingFacotr_y", (self._r), lowBound=0) # Set returns to scale if self.returns == "VRS": prob += pulp.lpSum([weight for weight 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]) # 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] 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 solve = DEAProblem(X, y, weight).solve()该模块依据了这个公式: 文章是张宁老师13年发表在RESR上的综述,
该模块可以自行设定投入X, 产出Y, 方向向量g, 以及权重向量w
后续还得考虑把undesirable output也加入进去。
我在编程的时候发现产出扩张系数是有可能大于1的,我以前一直以为扩张系数就是无效率值,发现还是有些不一样的。
感兴趣的可以私信我交流DEA、能源、环境、生命周期分析等等的工作。
——————更新—————— 考虑非期望产出的NDDF 考虑强\弱处置性的非期望产出NDDF