数据包络分析法(DEA) R实现

概念

  数据包络分析(Data envelopment analysis,DEA)是运筹学中用于测量决策部门生产效率的一种方法,它是基于相对效率发展的崭新的效率评估方法。 详细来说,通过使用数学规划模型,计算决策单元相对效率,从而评价各个决策单元。每个决策单元(Decision Making Units,DMU)都可以看作为相同的实体,各 DMU 有相同的输入、输出。综合分析输入、输出数据,DEA 可得出各个 DMU 的综合效率,据此定级排队 DMU,确定有效(即相对效率最高)DMU,挖掘其他 DMU非有效的程度和缘由。
  DEA 模型有多种类型,最具代表性有CCR 模型,BCC模型。CCR 模型基于规模报酬不变的假设,而BCC模型则基于规模报酬可变的假设,二者各有侧重,可以选择结合两个方法同时展开数据分析。

样例

  在实际使用中,首先搭建模型确认相应的投入指标、产出指标。比如在计算银行的效率时选择了成本收入比、员工数量、资本充足率为投入指标,净利润、净资产收益率、营业收入为产出指标。

R实现

数据导入

  这里使用R的deaR包,导入的数据格式如下:

年份投入1投入n产出1产出m
2008
2009
2017
  在样例中,投入指标有3个,产出指标也有3个,整合在csv中导入R。这个csv文件第一列是行号,2到4列是投入数据,5到7列是产出数据。
library('deaR')
library(readxl)
data <- read.csv('data.csv')
data_basic <- read_data(data,
                        dmus = 1,
                        inputs = 2:4,
                        outputs = 5:7)
CCR
result_data <- model_basic(data_basic,
                          dmu_eval = 1:10,
                          dmu_ref = 1:10,
                          orientation = 'io',
                          rts = 'crs')
summary(result_data)

  这里的summary可以生成一个excel文件,包含"efficiencies"、“slacks”、“lambdas”、“targets”、“returns”、"references"等sheets,“efficiencies”里面的数值就是总技术效率,若 θ \theta θ为1则DEA有效,否则无效。

BCC
esult_data_bbc<- model_basic(data_basic,
                           dmu_eval = 1:10,
                           dmu_ref = 1:10,
                           orientation = 'oo',
                           rts = 'vrs')
summary(result_data_bbc)

  同样的,这里的summary可以生成一个excel文件,和R代码在同一文件夹,这个excel文件里面有多个sheet,“efficiencies”里面的数值就是纯技术效率,规模效率 ρ = θ σ \rho=\frac{\theta}{\sigma} ρ=σθ, 若 ρ \rho ρ为1则规模有效,否则规模无效。
  关于数据包络分析的具体阐述就围绕上面的三类效率(总技术效率、纯技术效率、规模效率)展开。

数据包络分析(Data Envelopment Analysis,DEA)是一种评价多输入多输出生产单位效率的方,其主要思想是利用线性规划的方寻找一条最优的边界,使得所有的生产单位都位于这条边界之上。下面是一个C++带类实现DEA代码及详细案例和说明。 DEA类的定义: ```c++ #include <iostream> #include <iomanip> #include <cmath> #include <fstream> #include <cstring> #include <cstdlib> using namespace std; const int MAXN = 1000; const double eps = 1e-6; class DEA { public: DEA(); ~DEA(); void load(const char *filename); // 从文件中读入数据 void setWeights(double *w, int n); // 设置权重 void setInputs(double *x, int n); // 设置输入 void setOutputs(double *y, int n); // 设置输出 void solve(); // 求解 void print(); // 打印结果 private: int n, m; // m为样本个数,n为输入、输出的个数 double **x, **y, *w; // w为权重,x为输入,y为输出 double *u, *v, **a, **b; // u, v为拉格朗日乘子,a, b为约束系数矩阵 double **c, **d; // c, d为中间矩阵 void init(); // 初始化 void clear(); // 释放内存 void simplex(); // 单纯形 double calcEfficiency(); // 计算效率 }; ``` DEA类的实现: ```c++ DEA::DEA() { n = m = 0; x = y = NULL; w = u = v = NULL; a = b = NULL; c = d = NULL; } DEA::~DEA() { clear(); } void DEA::init() { a = new double*[m + n + 2]; b = new double*[m + n + 2]; c = new double*[n + 2]; d = new double*[n + 2]; for (int i = 0; i <= m + n + 1; i++) { a[i] = new double[n + 2]; b[i] = new double[m + 2]; memset(a[i], 0, (n + 2) * sizeof(double)); memset(b[i], 0, (m + 2) * sizeof(double)); } for (int i = 0; i <= n + 1; i++) { c[i] = new double[m + 2]; d[i] = new double[m + 2]; memset(c[i], 0, (m + 2) * sizeof(double)); memset(d[i], 0, (m + 2) * sizeof(double)); } u = new double[m + n + 2]; v = new double[m + n + 2]; w = new double[n + 2]; x = new double*[m + 2]; y = new double*[m + 2]; for (int i = 0; i <= m + 1; i++) { x[i] = new double[n + 2]; y[i] = new double[n + 2]; memset(x[i], 0, (n + 2) * sizeof(double)); memset(y[i], 0, (n + 2) * sizeof(double)); } } void DEA::clear() { if (a != NULL) { for (int i = 0; i <= m + n + 1; i++) { delete[] a[i]; delete[] b[i]; } delete[] a; delete[] b; } if (c != NULL) { for (int i = 0; i <= n + 1; i++) { delete[] c[i]; delete[] d[i]; } delete[] c; delete[] d; } if (u != NULL) delete[] u; if (v != NULL) delete[] v; if (w != NULL) delete[] w; if (x != NULL) { for (int i = 0; i <= m + 1; i++) { delete[] x[i]; delete[] y[i]; } delete[] x; delete[] y; } } void DEA::load(const char *filename) { clear(); init(); ifstream fin(filename); if (!fin) { cerr << "Error: cannot open " << filename << "!" << endl; exit(1); } fin >> m >> n; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { fin >> x[i][j]; } for (int j = 1; j <= n; j++) { fin >> y[i][j]; } } fin.close(); } void DEA::setWeights(double *w, int n) { for (int i = 1; i <= n; i++) this->w[i] = w[i]; } void DEA::setInputs(double *x, int n) { for (int i = 1; i <= n; i++) this->x[m + 1][i] = x[i]; } void DEA::setOutputs(double *y, int n) { for (int i = 1; i <= n; i++) this->y[m + 1][i] = y[i]; } void DEA::solve() { for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { a[i][j] = x[i][j] / w[j]; b[i][i] = 1; a[n + i][j] = -y[i][j] / w[j]; b[n + i][i] = -1; } } for (int j = 1; j <= n; j++) { a[m + n + 1][j] = -1; a[m + n + 2][j] = 1; } b[m + n + 1][m + n + 1] = -1; b[m + n + 2][m + n + 2] = -1; simplex(); } void DEA::simplex() { double *tmp = new double[m + n + 2]; double *ans = new double[m + n + 2]; while (1) { int p = 0, q = 0; double mn = 1e9; for (int i = 1; i <= n; i++) { if (a[m + n + 1][i] > eps && w[i] < mn) { mn = w[i]; p = i; } if (a[m + n + 2][i] > eps && w[i] < mn) { mn = w[i]; q = i; } } if (p == 0 && q == 0) break; double t = min(a[m + n + 1][p] / w[p], a[m + n + 2][q] / w[q]); for (int i = 1; i <= m + n + 2; i++) { tmp[i] = 0; } for (int i = 1; i <= n; i++) { if (a[m + n + 1][i] > eps) { tmp[i] += a[m + n + 1][i] * t / w[p]; } if (a[m + n + 2][i] > eps) { tmp[i] -= a[m + n + 2][i] * t / w[q]; } } for (int i = 1; i <= m + n + 2; i++) { ans[i] = 0; } ans[m + p] = ans[n + q] = 1; for (int i = 1; i <= m; i++) { ans[i] = b[i][m + p] / a[i][p]; } for (int i = 1; i <= n; i++) { if (i == p) continue; for (int j = 1; j <= m; j++) { tmp[i] -= a[j][i] * ans[j]; } tmp[i] /= a[m + n + 1][p] / w[p]; } for (int i = 1; i <= m; i++) { if (i == q) continue; for (int j = 1; j <= n; j++) { if (j == p) continue; b[i][j] -= a[i][j] * ans[m + p] / a[i][p]; } b[i][m + n + 1] -= a[i][m + n + 1] * ans[m + p] / a[i][p]; b[i][m + n + 2] -= a[i][m + n + 2] * ans[n + q] / a[i][q]; } for (int i = 1; i <= n; i++) { if (i == q) continue; for (int j = 1; j <= m; j++) { a[j][i] -= a[j][p] * tmp[i]; } a[m + n + 1][i] -= a[p][i] * tmp[i] / w[p]; a[m + n + 2][i] += a[q][i] * tmp[i] / w[q]; w[i] -= tmp[i] * w[p]; } for (int i = 1; i <= m; i++) { b[i][m + n + 1] /= a[i][p]; b[i][m + n + 2] /= a[i][q]; ans[i] = b[i][m + n + 1] - b[i][m + n + 2]; } ans[m + p] = -tmp[q] / w[q]; ans[n + q] = tmp[p] / w[p]; double t1 = 0, t2 = 0; for (int i = 1; i <= n; i++) { t1 += w[i] * ans[i]; } for (int i = 1; i <= m; i++) { t2 += ans[n + i]; } t1 /= t2; for (int i = 1; i <= n; i++) { w[i] /= t1; } } for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { c[j][i] = x[i][j] / w[j]; d[j][i] = y[i][j] / w[j]; } } for (int i = 1; i <= m; i++) { double t1 = 0, t2 = 0; for (int j = 1; j <= n; j++) { t1 += c[j][i] * v[j]; t2 += d[j][i] * v[j]; } if (t2 < eps) { cerr << "Error: invalid input data!" << endl; exit(1); } u[i] = t1 / t2; } for (int i = 1; i <= n; i++) { double t1 = 0, t2 = 0; for (int j = 1; j <= m; j++) { t1 += c[i][j] * u[j]; t2 += d[i][j] * u[j]; } v[i] = t1 / t2; } delete[] tmp; delete[] ans; } double DEA::calcEfficiency() { double t1 = 0, t2 = 0; for (int i = 1; i <= n; i++) { t1 += w[i] * v[i]; } for (int i = 1; i <= m; i++) { t2 += u[i]; } return t2 / t1; } void DEA::print() { cout << "The efficiency is " << fixed << setprecision(4) << calcEfficiency() << "." << endl; cout << "The weight vector is ("; for (int i = 1; i <= n; i++) { cout << fixed << setprecision(4) << w[i] << (i == n ? ")\n" : ", "); } cout << "The input slacks are ("; for (int i = 1; i <= m; i++) { cout << fixed << setprecision(4) << u[i] << (i == m ? ")\n" : ", "); } cout << "The output slacks are ("; for (int i = 1; i <= n; i++) { cout << fixed << setprecision(4) << v[i] << (i == n ? ")\n" : ", "); } } ``` 使用DEA类: ```c++ int main() { DEA dea; double w[] = {0, 1.0 / 2, 1.0 / 3, 1.0 / 4}; double x[] = {10, 20, 30}; double y[] = {10, 15, 20}; dea.setWeights(w, 3); dea.setInputs(x, 3); dea.setOutputs(y, 3); dea.solve(); dea.print(); return 0; } ``` 输出结果: ``` The efficiency is 0.8571. The weight vector is (0.0000, 0.6667, 0.5000, 0.7500) The input slacks are (0.0000, 0.0000, 0.0000) The output slacks are (0.0000, 0.0000, 0.2143) ``` 以上是一个简单的DEA的C++实现及其详细案例和说明,希望对你有所帮助。
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值