数据文件中一共有9年的优势概率数据,数据无缺失或多余空格,但根据代码跑出来的只有第一年(2015年)部分数据的结果。可以帮我找一下问题出在哪里,应该怎么改吗?
终端运行结果(部分,前面的调试信息省略):
GLPK Simplex Optimizer 5.0
278 rows, 10 columns, 1491 non-zeros
0: obj = 5.185936150e-05 inf = 1.367e+00 (141)
102: obj = 3.746395759e-04 inf = 9.833e-01 (8)
LP HAS NO PRIMAL FEASIBLE SOLUTION
处理年份: 2016 (136 个DMU)
未找到DMU 000012 (年份 2016) 的优势数据
(后省略,为年份2016所有DMU的数据均未找到)
处理年份: 2017 (136 个DMU)
未找到DMU 000012 (年份 2017) 的优势数据
(后省略,为年份2017所有DMU的数据均未找到)
处理年份: 2018 (92 个DMU)
未找到DMU 000012 (年份 2018) 的优势数据
未找到DMU 000027 (年份 2018) 的优势数据
未找到DMU 000039 (年份 2018) 的优势数据
未找到DMU 000055 (年份 2018) 的优势数据
未找到DMU 000059 (年份 2018) 的优势数据
未找到DMU 000099 (年份 2018) 的优势数据
未找到DMU 000100 (年份 2018) 的优势数据
未找到DMU 000400 (年份 2018) 的优势数据
未找到DMU 000421 (年份 2018) 的优势数据
未找到DMU 000507 (年份 2018) 的优势数据
未找到DMU 000544 (年份 2018) 的优势数据
未找到DMU 000554 (年份 2018) 的优势数据
未找到DMU 000582 (年份 2018) 的优势数据
未找到DMU 000601 (年份 2018) 的优势数据
未找到DMU 000652 (年份 2018) 的优势数据
未找到DMU 000656 (年份 2018) 的优势数据
未找到DMU 000672 (年份 2018) 的优势数据
未找到DMU 000685 (年份 2018) 的优势数据
未找到DMU 000690 (年份 2018) 的优势数据
未找到DMU 000778 (年份 2018) 的优势数据
未找到DMU 000883 (年份 2018) 的优势数据
未找到DMU 000885 (年份 2018) 的优势数据
未找到DMU 000937 (年份 2018) 的优势数据
未找到DMU 000967 (年份 2018) 的优势数据
未找到DMU 000973 (年份 2018) 的优势数据
未找到DMU 000983 (年份 2018) 的优势数据
未找到DMU 002009 (年份 2018) 的优势数据
未找到DMU 002019 (年份 2018) 的优势数据
未找到DMU 002039 (年份 2018) 的优势数据
未找到DMU 002060 (年份 2018) 的优势数据
未找到DMU 002062 (年份 2018) 的优势数据
未找到DMU 002065 (年份 2018) 的优势数据
未找到DMU 002074 (年份 2018) 的优势数据
未找到DMU 002080 (年份 2018) 的优势数据
未找到DMU 002111 (年份 2018) 的优势数据
未找到DMU 002128 (年份 2018) 的优势数据
未找到DMU 002130 (年份 2018) 的优势数据
未找到DMU 002135 (年份 2018) 的优势数据
未找到DMU 002169 (年份 2018) 的优势数据
未找到DMU 002202 (年份 2018) 的优势数据
未找到DMU 002218 (年份 2018) 的优势数据
未找到DMU 002221 (年份 2018) 的优势数据
未找到DMU 002266 (年份 2018) 的优势数据
未找到DMU 002267 (年份 2018) 的优势数据
未找到DMU 002271 (年份 2018) 的优势数据
未找到DMU 002276 (年份 2018) 的优势数据
未找到DMU 002300 (年份 2018) 的优势数据
未找到DMU 002318 (年份 2018) 的优势数据
未找到DMU 002368 (年份 2018) 的优势数据
未找到DMU 002389 (年份 2018) 的优势数据
未找到DMU 002394 (年份 2018) 的优势数据
未找到DMU 002443 (年份 2018) 的优势数据
未找到DMU 002451 (年份 2018) 的优势数据
未找到DMU 002457 (年份 2018) 的优势数据
未找到DMU 002479 (年份 2018) 的优势数据
未找到DMU 002523 (年份 2018) 的优势数据
未找到DMU 002531 (年份 2018) 的优势数据
未找到DMU 002545 (年份 2018) 的优势数据
未找到DMU 002573 (年份 2018) 的优势数据
未找到DMU 002594 (年份 2018) 的优势数据
未找到DMU 002672 (年份 2018) 的优势数据
未找到DMU 300021 (年份 2018) 的优势数据
未找到DMU 300118 (年份 2018) 的优势数据
未找到DMU 300185 (年份 2018) 的优势数据
未找到DMU 300190 (年份 2018) 的优势数据
未找到DMU 300332 (年份 2018) 的优势数据
未找到DMU 300355 (年份 2018) 的优势数据
未找到DMU 300376 (年份 2018) 的优势数据
未找到DMU 300433 (年份 2018) 的优势数据
未找到DMU 600075 (年份 2018) 的优势数据
未找到DMU 600089 (年份 2018) 的优势数据
未找到DMU 600107 (年份 2018) 的优势数据
未找到DMU 600116 (年份 2018) 的优势数据
未找到DMU 600143 (年份 2018) 的优势数据
未找到DMU 600163 (年份 2018) 的优势数据
未找到DMU 600170 (年份 2018) 的优势数据
未找到DMU 600176 (年份 2018) 的优势数据
未找到DMU 600188 (年份 2018) 的优势数据
未找到DMU 600236 (年份 2018) 的优势数据
未找到DMU 600256 (年份 2018) 的优势数据
未找到DMU 600268 (年份 2018) 的优势数据
未找到DMU 600269 (年份 2018) 的优势数据
未找到DMU 600277 (年份 2018) 的优势数据
未找到DMU 600310 (年份 2018) 的优势数据
未找到DMU 600320 (年份 2018) 的优势数据
未找到DMU 600323 (年份 2018) 的优势数据
未找到DMU 600348 (年份 2018) 的优势数据
未找到DMU 600395 (年份 2018) 的优势数据
未找到DMU 600438 (年份 2018) 的优势数据
未找到DMU 600483 (年份 2018) 的优势数据
未找到DMU 600487 (年份 2018) 的优势数据
未找到DMU 600505 (年份 2018) 的优势数据
计算完成,结果已保存至 model5_results.csv
PS D:\DEA_code>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glpk.h>
#include <math.h>
#include <dirent.h>
#include <windows.h>
#define MAX_LINE_LEN 1024
#define MAX_DMU 500
#define MAX_YEARS 10
#define η 0.02
#define δ 0.3
#define EPSILON 1e-6
typedef struct
{
int year;
char dmu[20];
double financial_expense;
double dividend;
double operating_cost;
double total_asset;
double employee;
double total_profit;
double operating_income;
double non_current_liabilities;
double paid_in_capital;
} DMU;
typedef struct
{
int year;
char dmu[20];
double self_eff;
double p_oe;
double p_se1;
double p_se2;
double p1;
double p2;
} DominanceData;
typedef struct
{
DMU *dmus;
DominanceData *dominance;
int count;
int year;
int total_dmus;
int total_years;
double total_p1;
double total_p2;
} YearGroup;
// 读取原始数据文件
DMU *read_dmu_data(const char *filename, int *count)
{
printf("\n[开始] 读取原始数据文件: %s\n", filename);
FILE *fp = fopen(filename, "r");
if (!fp)
{
fprintf(stderr, "无法打开文件: %s\n", filename);
return NULL;
}
DMU *data = malloc(MAX_DMU * sizeof(DMU));
if (!data)
{
fclose(fp);
fprintf(stderr, "错误:内存分配失败\n");
return NULL;
}
char line[MAX_LINE_LEN];
*count = 0;
// 跳过标题行
if (!fgets(line, sizeof(line), fp))
{
fclose(fp);
free(data);
fprintf(stderr, "警告:文件为空或读取标题行失败\n");
return NULL;
}
printf("数据格式验证通过,开始解析...\n");
while (fgets(line, sizeof(line), fp) && *count < MAX_DMU)
{
DMU *d = &data[*count];
int parsed = sscanf(line, "%d,%19[^,],%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
&d->year, d->dmu, &d->financial_expense, &d->dividend,
&d->operating_cost, &d->total_asset, &d->employee,
&d->total_profit, &d->operating_income,
&d->non_current_liabilities, &d->paid_in_capital);
if (parsed != 11)
{
fprintf(stderr, "解析错误[行%d]: %s", *count + 1, line);
continue;
}
(*count)++;
// 每读取100条记录打印进度
if (*count % 100 == 0)
{
printf("已解析 %d 条记录...\n", *count);
}
}
fclose(fp);
printf("[完成] 成功读取 %d 条原始数据记录\n", *count);
return data;
}
// 读取优势概率数据
DominanceData *read_dominance_data(const char *filename, int *count)
{
printf("\n[开始] 读取优势数据文件: %s\n", filename);
FILE *fp = fopen(filename, "r");
if (!fp)
{
fprintf(stderr, "错误:无法打开文件: %s\n", filename);
return NULL;
}
DominanceData *data = malloc(MAX_DMU * sizeof(DominanceData));
if (!data)
{
fclose(fp);
fprintf(stderr, "错误:内存分配失败\n");
return NULL;
}
char line[MAX_LINE_LEN];
*count = 0;
int line_num = 1; // 新增行号计数器
// 跳过标题行
if (!fgets(line, sizeof(line), fp))
{
fclose(fp);
free(data);
fprintf(stderr, "警告:文件为空或读取标题行失败\n");
return NULL;
}
printf("标题行验证通过,开始解析数据...\n");
while (fgets(line, sizeof(line), fp) && *count < MAX_DMU)
{
line_num++;
DominanceData *d = &data[*count];
// 注意:原结构体DominanceData有self_eff, p_oe, p_se1, p_se2, p1, p2共6个double字段,所以正确格式应为6个%lf
// 修改后的解析部分
int parsed = sscanf(line, "%d,%19[^,],%lf,%lf,%lf,%lf,%lf,%lf",
&d->year, d->dmu,
&d->self_eff,
&d->p_oe,
&d->p_se1,
&d->p_se2,
&d->p1,
&d->p2);
if (parsed != 8) // 现在期望8个字段
{
fprintf(stderr, "解析错误[行%d]:字段数量不足(期望8,实际%d)\n",
line_num, parsed);
fprintf(stderr, "问题内容:%s", line);
continue;
}
// 数据有效性检查
if (d->p_oe < 0 || d->p_oe > 1)
{
fprintf(stderr, "数据异常[行%d]:P_OE值超出范围(0-1): %.2f\n",
line_num, d->p_oe);
continue;
}
(*count)++;
// 每50行打印进度
if (*count % 50 == 0)
{
printf("已成功解析 %d 条记录...\n", *count);
}
}
fclose(fp);
if (*count == 0)
{
fprintf(stderr, "严重警告:未解析到任何有效数据!\n");
free(data);
return NULL;
}
printf("[完成] 成功读取 %d 条优势数据记录(共处理 %d 行)\n", *count, line_num);
return data;
}
double phi_transform(double x)
{
return (1 - exp(-η * x)) / η;
}
double risk_adjust(double prob)
{
return 1 - exp(-δ * prob);
}
double solve_optimization(DMU *dmu, DominanceData *dom,
DMU *all_dmus, int total_dmus,
int total_years, double total_p1, double total_p2)
{
glp_prob *lp = glp_create_prob();
glp_set_obj_dir(lp, GLP_MAX);
// 1. 定义变量 (列1~10)
glp_add_cols(lp, 10);
for (int i = 1; i <= 10; i++)
{
glp_set_col_bnds(lp, i, GLP_LO, 1e-6, 0.0); // 下限为1e-6
}
glp_set_col_bnds(lp, 10, GLP_DB, 0.0, 1.0); // 列10 μ ∈ [0,1]
// 2. 设置目标函数(列8和9)
double phi_y1 = phi_transform(dmu->operating_income);
double phi_y2 = phi_transform(dmu->total_profit);
glp_set_obj_coef(lp, 8, phi_y1); // 列8
glp_set_obj_coef(lp, 9, phi_y2); // 列9
// 3. 添加约束
int row_idx = 0;
const int total_constraints = 3 + 2 * total_dmus + 3;
glp_add_rows(lp, total_constraints);
// ------------------------------------------
// 约束1: u8*y8 + u9*y9 = self_eff
// ------------------------------------------
row_idx++;
glp_set_row_bnds(lp, row_idx, GLP_FX, dom->self_eff, dom->self_eff);
int ind1[] = {0, 8, 9}; // 列8和9
double val1[] = {0.0, dmu->operating_income, dmu->total_profit};
printf("[DEBUG] 约束1 (行 %d): 列索引 = [8, 9]\n", row_idx); // 调试输出
glp_set_mat_row(lp, row_idx, 2, ind1, val1);
// ------------------------------------------
// 约束2: 阶段一投入归一化(列1和2)
// ------------------------------------------
row_idx++;
glp_set_row_bnds(lp, row_idx, GLP_FX, 0.5, 0.5);
int ind2[] = {0, 1, 2}; // 列1和2
double val2[] = {0.0, dmu->financial_expense, dmu->dividend};
printf("[DEBUG] 约束2 (行 %d): 列索引 = [1, 2]\n", row_idx); // 调试输出
glp_set_mat_row(lp, row_idx, 2, ind2, val2);
// ------------------------------------------
// 约束3: 阶段二投入归一化(列3,4,5)
// ------------------------------------------
row_idx++;
glp_set_row_bnds(lp, row_idx, GLP_FX, 0.5, 0.5);
int ind3[] = {0, 3, 4, 5}; // 列3,4,5
double val3[] = {0.0, dmu->operating_cost, dmu->total_asset, dmu->employee};
printf("[DEBUG] 约束3 (行 %d): 列索引 = [3, 4, 5]\n", row_idx); // 调试输出
glp_set_mat_row(lp, row_idx, 3, ind3, val3);
// ------------------------------------------
// 4. 处理所有DMU的约束
// ------------------------------------------
for (int j = 0; j < total_dmus; j++)
{
DMU *other = &all_dmus[j];
// 阶段一约束(列1,2,6,7)
row_idx++;
glp_set_row_bnds(lp, row_idx, GLP_LO, 0.0, 0.0);
int ind_stage1[] = {0, 1, 2, 6, 7}; // 列1,2,6,7
double val_stage1[] = {0.0,
other->financial_expense,
other->dividend,
-other->non_current_liabilities,
-other->paid_in_capital};
printf("[DEBUG] DMU阶段1 (行 %d): 列索引 = [1, 2, 6, 7]\n", row_idx); // 调试输出
glp_set_mat_row(lp, row_idx, 4, ind_stage1, val_stage1);
// 阶段二约束(列3,4,5,6,7,8,9)
row_idx++;
glp_set_row_bnds(lp, row_idx, GLP_LO, 0.0, 0.0);
int ind_stage2[] = {0, 3, 4, 5, 6, 7, 8, 9}; // 列3~9
double val_stage2[] = {0.0,
other->operating_cost,
other->total_asset,
other->employee,
other->non_current_liabilities,
other->paid_in_capital,
-other->operating_income,
-other->total_profit};
printf("[DEBUG] DMU阶段2 (行 %d): 列索引 = [3, 4, 5, 6, 7, 8, 9]\n", row_idx); // 调试输出
glp_set_mat_row(lp, row_idx, 7, ind_stage2, val_stage2);
}
// ------------------------------------------
// 5. 风险约束
// ------------------------------------------
// 风险约束1: μ = p_oe
row_idx++;
glp_set_row_bnds(lp, row_idx, GLP_FX, dom->p_oe, dom->p_oe);
int ind_risk1[] = {0, 10};
double val_risk1[] = {0.0, 1.0};
glp_set_mat_row(lp, row_idx, 1, ind_risk1, val_risk1);
// 风险约束2: 阶段一风险调整(使用当前DMU的p1)
row_idx++;
double rhs_p1 = dom->p1;
glp_set_row_bnds(lp, row_idx, GLP_FX, rhs_p1, rhs_p1);
int ind_risk2[] = {0, 1, 2};
double val_risk2[] = {0.0,
phi_transform(dmu->financial_expense) * dmu->financial_expense,
phi_transform(dmu->dividend) * dmu->dividend};
glp_set_mat_row(lp, row_idx, 2, ind_risk2, val_risk2);
// 风险约束3: 阶段二风险调整(使用当前DMU的p2)
row_idx++;
double rhs_p2 = dom->p2;
glp_set_row_bnds(lp, row_idx, GLP_FX, rhs_p2, rhs_p2);
int ind_risk3[] = {0, 3, 4, 5};
double val_risk3[] = {0.0,
phi_transform(dmu->operating_cost) * dmu->operating_cost,
phi_transform(dmu->total_asset) * dmu->total_asset,
phi_transform(dmu->employee) * dmu->employee};
glp_set_mat_row(lp, row_idx, 3, ind_risk3, val_risk3);
// ------------------------------------------
// 6. 求解并返回结果
// ------------------------------------------
int status = glp_simplex(lp, NULL);
if (status != 0)
{
fprintf(stderr, "[错误] GLPK求解失败 (状态码: %d)\n", status);
glp_delete_prob(lp);
return NAN;
}
double eff = glp_get_obj_val(lp);
double mu = glp_get_col_prim(lp, 10);
// 风险调整计算
double adj = mu * (risk_adjust(dom->p_oe) +
risk_adjust(dom->p1) +
risk_adjust(dom->p2)) +
(1 - mu) * (risk_adjust(1 - dom->p_oe) +
risk_adjust(1 - dom->p1) +
risk_adjust(1 - dom->p2));
glp_delete_prob(lp);
return eff + adj;
}
void process_year(YearGroup *group, DominanceData *dominance, int dom_count,
DMU *all_dmus, int total_dmus)
{
FILE *output = fopen("model5_results.csv", "a");
if (!output)
{
fprintf(stderr, "无法打开输出文件\n");
return;
}
for (int i = 0; i < group->count; i++)
{
DMU *dmu = &group->dmus[i];
DominanceData *dom = NULL;
// 查找匹配的优势数据
for (int j = 0; j < dom_count; j++)
{
if (group->year == dominance[j].year &&
strcmp(dmu->dmu, dominance[j].dmu) == 0)
{
dom = &dominance[j];
break;
}
}
if (!dom)
{
fprintf(stderr, "未找到DMU %s (年份 %d) 的优势数据\n", dmu->dmu, group->year);
continue;
}
double eff = solve_optimization(dmu, dom, group->dmus,
group->total_dmus,
group->total_years,
group->total_p1,
group->total_p2);
if (!isnan(eff))
{
fprintf(output, "%d,%s,%.4f\n", group->year, dmu->dmu, eff);
}
}
fclose(output);
}
int main()
{
// 设置控制台输出编码为UTF-8
SetConsoleOutputCP(65001);
printf("\n======== 程序启动 ========\n");
printf("版本:Model5 (带风险调整)\n");
printf("参数:η=%.2f, δ=%.1f\n", η, δ);
// 读取数据
printf("==== 数据加载阶段 ====\n");
int dmu_count = 0;
DMU *all_dmus = read_dmu_data("./Data_2023.12.20_1.csv", &dmu_count);
if (!all_dmus || dmu_count == 0)
{
fprintf(stderr, "\n错误:原始数据读取失败,程序终止\n");
return EXIT_FAILURE;
}
printf("\n--> 原始数据加载完成 <--\n");
int dom_count = 0;
DominanceData *dominance = read_dominance_data("dominance_results.csv", &dom_count);
if (!dominance || dom_count == 0)
{
free(all_dmus);
fprintf(stderr, "\n错误:优势数据读取失败,请检查:\n");
fprintf(stderr, "1. 文件是否存在\n2. 数据格式是否正确\n3. 数值范围是否合法\n");
return EXIT_FAILURE;
}
printf("\n--> 优势数据加载完成 <--\n");
// 计算全局统计量
double total_p1 = 0.0, total_p2 = 0.0;
for (int i = 0; i < dom_count; i++)
{
total_p1 += dominance[i].p1;
total_p2 += dominance[i].p2;
}
// 按年份分组
YearGroup years[MAX_YEARS] = {0};
int year_count = 0;
// 第一次遍历:识别所有年份
int unique_years[MAX_YEARS] = {0};
for (int i = 0; i < dmu_count; i++)
{
int exists = 0;
for (int y = 0; y < year_count; y++)
{
if (unique_years[y] == all_dmus[i].year)
{
exists = 1;
break;
}
}
if (!exists && year_count < MAX_YEARS)
{
unique_years[year_count++] = all_dmus[i].year;
}
}
// 分配内存并初始化年份组
for (int y = 0; y < year_count; y++)
{
years[y].year = unique_years[y];
years[y].count = 0;
// 统计该年份DMU数量
for (int i = 0; i < dmu_count; i++)
{
if (all_dmus[i].year == unique_years[y])
{
years[y].count++;
}
}
years[y].dmus = malloc(years[y].count * sizeof(DMU));
if (!years[y].dmus)
{
fprintf(stderr, "内存分配失败\n");
// 清理已分配内存
for (int i = 0; i < y; i++)
free(years[i].dmus);
free(all_dmus);
free(dominance);
return EXIT_FAILURE;
}
// 填充数据
int idx = 0;
for (int i = 0; i < dmu_count; i++)
{
if (all_dmus[i].year == unique_years[y])
{
years[y].dmus[idx++] = all_dmus[i];
}
}
// 设置统计参数
years[y].total_dmus = years[y].count;
years[y].total_years = year_count;
years[y].total_p1 = total_p1;
years[y].total_p2 = total_p2;
}
// 处理每个年份
for (int y = 0; y < year_count; y++)
{
printf("处理年份: %d (%d 个DMU)\n", years[y].year, years[y].count);
process_year(&years[y], dominance, dom_count,
all_dmus, dmu_count); // 传递全局数据
}
// 清理内存
for (int y = 0; y < year_count; y++)
{
free(years[y].dmus);
}
free(all_dmus);
free(dominance);
printf("计算完成,结果已保存至 model5_results.csv\n");
return EXIT_SUCCESS;
}