Quellcode durchsuchen

算法集结

Signed-off-by: codeClown <zhaomengshou@126.com>
codeClown vor 1 Jahr
Ursprung
Commit
bb4ee53ed9
3 geänderte Dateien mit 522 neuen und 0 gelöschten Zeilen
  1. 2 0
      QFD/QFD.pro
  2. 454 0
      QFD/common/MindEvaluation.cpp
  3. 66 0
      QFD/common/MindEvaluation.h

+ 2 - 0
QFD/QFD.pro

@@ -76,6 +76,7 @@ SOURCES += \
     algorithm/test_main.cpp \
     common/EvalDataManager.cpp \
     common/ExpertManager.cpp \
+    common/MindEvaluation.cpp \
     common/ProjectManager.cpp \
     common/QFDAlert.cpp \
     common/QFDConfig.cpp \
@@ -145,6 +146,7 @@ HEADERS += \
     algorithm/ZScore.h \
     common/EvalDataManager.h \
     common/ExpertManager.h \
+    common/MindEvaluation.h \
     common/ProjectManager.h \
     common/QFDAlert.h \
     common/QFDConfig.h \

+ 454 - 0
QFD/common/MindEvaluation.cpp

@@ -0,0 +1,454 @@
+#include "MindEvaluation.h"
+#include "CMind.h"
+#include "dbService/NodeMatrixService.h"
+#include "dbService/UserConfigService.h"
+#include "algorithm/HierarchicalAnalysis.h"
+#include "algorithm/EntropyWeights.h"
+#include "algorithm/PCA.h"
+
+#include <QMessageBox>
+#include <QDebug>
+
+MindEvaluation::MindEvaluation(CMind *mind, int expertId, const QString &tableType, int mindMatrix, QObject *parent)
+    : QObject(parent),
+      m_mind(mind),
+      m_expertId(expertId),
+      m_tableType(tableType),
+      m_mindMatrix(mindMatrix),
+      m_isAggregationOp(false)
+{
+    init();
+}
+
+MindEvaluation::MindEvaluation(CMind *mind, MindEvaluation::AggregationType atype, const QString &tableType,
+                               int mindMatrix, QObject *parent)
+    : QObject(parent),
+      m_mind(mind),
+      m_tableType(tableType),
+      m_mindMatrix(mindMatrix),
+      m_aggregationType(atype),
+      m_isAggregationOp(true)
+{
+}
+
+MindEvaluation::~MindEvaluation() { }
+
+void MindEvaluation::updateSeqNodes()
+{
+    m_mind->getSeqNodes(m_seqNodes);
+}
+
+static QList<QPair<QString, QString>> getMatrixString(const QStringList &in)
+{
+    QList<QPair<QString, QString>> res;
+    const int n = in.size();
+    for (int i = 0; i < n; ++i) {
+        for (int j = 0; j < n; ++j) {
+            res << QPair<QString, QString>(in.at(i), in.at(j));
+        }
+    }
+
+    return res;
+}
+
+void MindEvaluation::computeWeights()
+{
+    if (!m_isAggregationOp) {
+        computeSingleWeights();
+    } else {
+        if (m_aggregationType == NoMerge) {
+            computeNoMergeWeights();
+        } else {
+            computeMergeWeights();
+        }
+    }
+}
+
+void MindEvaluation::init()
+{
+    updateSeqNodes();
+}
+
+void MindEvaluation::computeSingleWeights()
+{
+    QList<NodeMatrixInfo *> nmInfos;
+    if (NodeMatrixService().QueryNodeMatrixListByExpertIdAndEngineerId2(&nmInfos, m_expertId, m_mind->root().projectId,
+                                                                        m_tableType)) {
+        QMessageBox::warning(nullptr, "警告", "数据库访问失败");
+        return;
+    }
+
+    for (int sn = 0; sn < m_seqNodes.count(); sn++) {
+        qDebug() << "第" << sn << "层";
+        for (auto s : m_seqNodes.at(sn)) {
+            qDebug() << s.name << s.childs;
+
+            if (m_mindMatrix == 0) {  // 层次分析法
+                auto matrixStr = getMatrixString(s.childs);
+                QVector<qreal> nxnValus(matrixStr.size(), 0.0001);  // n x n矩阵
+
+                for (const auto &nmInfo : nmInfos) {
+                    if (nmInfo->mindId == m_mindMatrix) {
+                        int loc = matrixStr.indexOf(QPair<QString, QString>(nmInfo->abscissa, nmInfo->ordinate));
+                        if (loc >= 0) {
+                            QStringList nodeValue = nmInfo->nodeValue.split("/");
+                            if (nodeValue.size() == 1) {
+                                nxnValus[loc] = nodeValue[0].toDouble();
+                            } else {
+                                nxnValus[loc] = nodeValue[0].toDouble() / nodeValue[1].toDouble();
+                            }
+                        }
+                    }
+                }
+                QScopedPointer<HierarchicalAnalysis> ha(new HierarchicalAnalysis(s.childs, nxnValus));
+                QVector<qreal> weights = ha->getWeights();
+
+                for (int c = 0; c < s.childs.size(); ++c) {
+                    mindNodeWeights << MindNodeItem { s.name, s.childs.at(c), weights.at(c), 0 };
+                }
+            } else {
+
+                // 熵权法
+                if (1) {
+                    QMap<QString /*指标*/, QMap<QString /*uuid*/, double>> seqMap;
+                    for (const auto &nmInfo : nmInfos) {
+                        if (nmInfo->mindId == m_mindMatrix) {
+                            int loc = s.childs.indexOf(nmInfo->abscissa);  // 指标索引
+                            if (loc >= 0) {
+                                QStringList nodeValue = nmInfo->nodeValue.split("/");
+                                double v;
+                                if (nodeValue.size() == 1) {
+                                    v = nodeValue[0].toDouble();
+                                } else {
+                                    v = nodeValue[0].toDouble() / nodeValue[1].toDouble();
+                                }
+
+                                if (!seqMap.contains(nmInfo->abscissa)) {
+                                    seqMap.insert(nmInfo->abscissa, QMap<QString /*uuid*/, double>());
+                                }
+                                seqMap[nmInfo->abscissa].insert(nmInfo->strUuid, v);
+                            }
+                        }
+                    }
+
+                    EntropyMat eMat;  // 一个指标一行数据
+                    for (const auto &c : s.childs) {
+                        if (seqMap.contains(c)) {
+                            QVector<double> indexVecs;
+
+                            QMapIterator<QString, double> iter(seqMap[c]);
+                            while (iter.hasNext()) {
+                                iter.next();
+                                indexVecs << iter.value();
+                            }
+
+                            eMat << indexVecs;
+                        } else {
+                            QMessageBox::warning(nullptr, "警告", QString("指标%1数据缺失").arg(c));
+                        }
+                    }
+
+                    QScopedPointer<EntropyWeights> ew(new EntropyWeights(eMat));
+                    QVector<qreal> weights, score;
+                    ew->compute(weights, score);
+
+                    for (int c = 0; c < s.childs.size(); ++c) {
+                        mindNodeWeights << MindNodeItem { s.name, s.childs.at(c), weights.at(c), score.at(c) };
+                    }
+                } else {  // pca
+                    QMap<QString /*uuid*/, QMap<QString /*指标*/, double>> seqMap;
+                    for (const auto &nmInfo : nmInfos) {
+                        if (nmInfo->mindId == m_mindMatrix) {
+                            int loc = s.childs.indexOf(nmInfo->abscissa);  // 指标索引
+                            if (loc >= 0) {
+                                QStringList nodeValue = nmInfo->nodeValue.split("/");
+                                double v;
+                                if (nodeValue.size() == 1) {
+                                    v = nodeValue[0].toDouble();
+                                } else {
+                                    v = nodeValue[0].toDouble() / nodeValue[1].toDouble();
+                                }
+
+                                if (!seqMap.contains(nmInfo->strUuid)) {
+                                    seqMap.insert(nmInfo->strUuid, QMap<QString /*指标*/, double>());
+                                }
+                                seqMap[nmInfo->strUuid].insert(nmInfo->abscissa, v);
+                            }
+                        }
+                    }
+
+                    QVector<QVector<double>> pMat;  // 一个指标一列数据
+
+                    QMapIterator<QString, QMap<QString /*指标*/, double>> iter(seqMap);
+
+                    while (iter.hasNext()) {
+                        iter.next();
+                        QMap<QString /*指标*/, double> indexMap = iter.value();
+
+                        QVector<double> tmp;
+                        QMapIterator<QString /*指标*/, double> iterIndex(indexMap);
+                        while (iterIndex.hasNext()) {
+                            iterIndex.next();
+                            tmp << iterIndex.value();
+                        }
+                        pMat << tmp;
+                    }
+
+                    QScopedPointer<PCA> pca(new PCA(pMat));
+                    pca->compute();
+                    QVector<qreal> weights = pca->weights();
+                    QVector<qreal> score   = pca->scores();
+                    for (int c = 0; c < s.childs.size(); ++c) {
+                        mindNodeWeights << MindNodeItem { s.name, s.childs.at(c), weights.at(c), score.at(c) };
+                    }
+                }
+            }
+        }
+    }
+
+    qDeleteAll(nmInfos);
+}
+
+/// 数据集结,先计算每个专家的权重,在求均值
+void MindEvaluation::computeNoMergeWeights()
+{
+    int enjId = m_mind->root().projectId;
+    QList<UserConfig *> users;
+
+    if (UserConfigService().QueryUserConfigListInfoByEngineerId(&users, enjId)) {
+        QMessageBox::warning(nullptr, "警告", "数据库访问失败");
+        return;
+    }
+
+    bool QueryUserConfigListInfoByEngineerId(QList<UserConfig *> * userCfgList, int engineerId);
+
+    QScopedPointer<QList<QList<MindNodeItem>>> allItems(new QList<QList<MindNodeItem>>());
+
+    for (const auto &user : users) {
+        QList<NodeMatrixInfo *> nmInfos;
+        if (NodeMatrixService().QueryNodeMatrixListByExpertIdAndEngineerId2(&nmInfos, user->id, enjId, m_tableType)) {
+            qDeleteAll(users);
+            QMessageBox::warning(nullptr, "警告", "数据库访问失败");
+            return;
+        }
+        QList<MindNodeItem> mnItem;
+
+        computeOneEntry(nmInfos, mnItem);
+        allItems->append(mnItem);
+
+        qDeleteAll(nmInfos);
+    }
+    qDeleteAll(users);
+
+    for (int i = 0; i < allItems->size(); ++i) {
+        if (i == 0) {
+            mindNodeWeights = allItems->at(0);
+        } else {
+            for (const auto &item : allItems->at(i)) {
+                int id = mindNodeWeights.indexOf(item);
+                mindNodeWeights[id].value += item.value;
+                mindNodeWeights[id].score += item.score;
+            }
+        }
+    }
+
+    for (int id = 0; id < mindNodeWeights.size(); id++) {
+        mindNodeWeights[id].value /= allItems->size();
+        mindNodeWeights[id].score /= allItems->size();
+    }
+}
+
+/// 数矩阵集结,先计算出一个综合专家,在计算权重
+void MindEvaluation::computeMergeWeights()
+{
+    int enjId = m_mind->root().projectId;
+    QList<UserConfig *> users;
+
+    if (UserConfigService().QueryUserConfigListInfoByEngineerId(&users, enjId)) {
+        QMessageBox::warning(nullptr, "警告", "数据库访问失败");
+        return;
+    }
+
+    bool QueryUserConfigListInfoByEngineerId(QList<UserConfig *> * userCfgList, int engineerId);
+
+    QList<NodeMatrixInfo *> megerNMInfo;
+    QVector<double> nodeValues;
+
+    for (const auto &user : users) {
+        QList<NodeMatrixInfo *> nmInfos;
+        if (NodeMatrixService().QueryNodeMatrixListByExpertIdAndEngineerId2(&nmInfos, user->id, enjId, m_tableType)) {
+            qDeleteAll(users);
+            QMessageBox::warning(nullptr, "警告", "数据库访问失败");
+            return;
+        }
+
+        if (megerNMInfo.size() == 0) {
+            for (int nm = 0; nm < nmInfos.size(); ++nm) {
+                NodeMatrixInfo *info = nmInfos.at(nm);
+                megerNMInfo.append(new NodeMatrixInfo());
+                *megerNMInfo[0] = *info;
+                double v;
+                QStringList nds = nmInfos.at(nm)->nodeValue.split("/");
+                if (nds.size() == 1) {
+                    v = nds.at(0).toDouble();
+                } else {
+                    v = nds.at(0).toDouble() / nds.at(1).toDouble();
+                }
+                nodeValues << v;
+            }
+        } else {
+            for (int nm = 0; nm < nmInfos.size(); ++nm) {
+                double v;
+                QStringList nds = nmInfos.at(nm)->nodeValue.split("/");
+                if (nds.size() == 1) {
+                    v = nds.at(0).toDouble();
+                } else {
+                    v = nds.at(0).toDouble() / nds.at(1).toDouble();
+                }
+                nodeValues[nm] += v;
+            }
+        }
+
+        qDeleteAll(nmInfos);
+    }
+
+    for (int nm = 0; nm < megerNMInfo.size(); ++nm) {
+        megerNMInfo[nm]->nodeValue = QString::number(nodeValues[nm] / users.size());
+    }
+
+    computeOneEntry(megerNMInfo, mindNodeWeights);
+
+    qDeleteAll(megerNMInfo);
+    qDeleteAll(users);
+}
+
+void MindEvaluation::computeOneEntry(const QList<NodeMatrixInfo *> &nmInfos, QList<MindNodeItem> &mindNodeItem)
+{
+    for (int sn = 0; sn < m_seqNodes.count(); sn++) {
+        qDebug() << "第" << sn << "层";
+        for (auto s : m_seqNodes.at(sn)) {
+            qDebug() << s.name << s.childs;
+
+            if (m_mindMatrix == 0) {  // 层次分析法
+                auto matrixStr = getMatrixString(s.childs);
+                QVector<qreal> nxnValus(matrixStr.size(), 0.0001);  // n x n矩阵
+
+                for (const auto &nmInfo : nmInfos) {
+                    if (nmInfo->mindId == m_mindMatrix) {
+                        int loc = matrixStr.indexOf(QPair<QString, QString>(nmInfo->abscissa, nmInfo->ordinate));
+                        if (loc >= 0) {
+                            QStringList nodeValue = nmInfo->nodeValue.split("/");
+                            if (nodeValue.size() == 1) {
+                                nxnValus[loc] = nodeValue[0].toDouble();
+                            } else {
+                                nxnValus[loc] = nodeValue[0].toDouble() / nodeValue[1].toDouble();
+                            }
+                        }
+                    }
+                }
+                QScopedPointer<HierarchicalAnalysis> ha(new HierarchicalAnalysis(s.childs, nxnValus));
+                QVector<qreal> weights = ha->getWeights();
+
+                for (int c = 0; c < s.childs.size(); ++c) {
+                    mindNodeItem << MindNodeItem { s.name, s.childs.at(c), weights.at(c), 0 };
+                }
+            } else {
+
+                // 熵权法
+                if (1) {
+                    QMap<QString /*指标*/, QMap<QString /*uuid*/, double>> seqMap;
+                    for (const auto &nmInfo : nmInfos) {
+                        if (nmInfo->mindId == m_mindMatrix) {
+                            int loc = s.childs.indexOf(nmInfo->abscissa);  // 指标索引
+                            if (loc >= 0) {
+                                QStringList nodeValue = nmInfo->nodeValue.split("/");
+                                double v;
+                                if (nodeValue.size() == 1) {
+                                    v = nodeValue[0].toDouble();
+                                } else {
+                                    v = nodeValue[0].toDouble() / nodeValue[1].toDouble();
+                                }
+
+                                if (!seqMap.contains(nmInfo->abscissa)) {
+                                    seqMap.insert(nmInfo->abscissa, QMap<QString /*uuid*/, double>());
+                                }
+                                seqMap[nmInfo->abscissa].insert(nmInfo->strUuid, v);
+                            }
+                        }
+                    }
+
+                    EntropyMat eMat;  // 一个指标一行数据
+                    for (const auto &c : s.childs) {
+                        if (seqMap.contains(c)) {
+                            QVector<double> indexVecs;
+
+                            QMapIterator<QString, double> iter(seqMap[c]);
+                            while (iter.hasNext()) {
+                                iter.next();
+                                indexVecs << iter.value();
+                            }
+
+                            eMat << indexVecs;
+                        } else {
+                            QMessageBox::warning(nullptr, "警告", QString("指标%1数据缺失").arg(c));
+                        }
+                    }
+
+                    QScopedPointer<EntropyWeights> ew(new EntropyWeights(eMat));
+                    QVector<qreal> weights, score;
+                    ew->compute(weights, score);
+
+                    for (int c = 0; c < s.childs.size(); ++c) {
+                        mindNodeItem << MindNodeItem { s.name, s.childs.at(c), weights.at(c), score.at(c) };
+                    }
+                } else {  // pca
+                    QMap<QString /*uuid*/, QMap<QString /*指标*/, double>> seqMap;
+                    for (const auto &nmInfo : nmInfos) {
+                        if (nmInfo->mindId == m_mindMatrix) {
+                            int loc = s.childs.indexOf(nmInfo->abscissa);  // 指标索引
+                            if (loc >= 0) {
+                                QStringList nodeValue = nmInfo->nodeValue.split("/");
+                                double v;
+                                if (nodeValue.size() == 1) {
+                                    v = nodeValue[0].toDouble();
+                                } else {
+                                    v = nodeValue[0].toDouble() / nodeValue[1].toDouble();
+                                }
+
+                                if (!seqMap.contains(nmInfo->strUuid)) {
+                                    seqMap.insert(nmInfo->strUuid, QMap<QString /*指标*/, double>());
+                                }
+                                seqMap[nmInfo->strUuid].insert(nmInfo->abscissa, v);
+                            }
+                        }
+                    }
+
+                    QVector<QVector<double>> pMat;  // 一个指标一列数据
+
+                    QMapIterator<QString, QMap<QString /*指标*/, double>> iter(seqMap);
+
+                    while (iter.hasNext()) {
+                        iter.next();
+                        QMap<QString /*指标*/, double> indexMap = iter.value();
+
+                        QVector<double> tmp;
+                        QMapIterator<QString /*指标*/, double> iterIndex(indexMap);
+                        while (iterIndex.hasNext()) {
+                            iterIndex.next();
+                            tmp << iterIndex.value();
+                        }
+                        pMat << tmp;
+                    }
+
+                    QScopedPointer<PCA> pca(new PCA(pMat));
+                    pca->compute();
+                    QVector<qreal> weights = pca->weights();
+                    QVector<qreal> score   = pca->scores();
+                    for (int c = 0; c < s.childs.size(); ++c) {
+                        mindNodeItem << MindNodeItem { s.name, s.childs.at(c), weights.at(c), score.at(c) };
+                    }
+                }
+            }
+        }
+    }
+}

+ 66 - 0
QFD/common/MindEvaluation.h

@@ -0,0 +1,66 @@
+#ifndef MINDEVALUATION_H
+#define MINDEVALUATION_H
+
+#include <QObject>
+#include "CMind.h"
+#include "dbService/ClassSet.h"
+
+struct MindNodeItem
+{
+    QString parent;  // 节点名
+    QString name;
+    double value;
+    double score;
+
+    bool operator==(const MindNodeItem &rhs) { return parent == rhs.parent && name == rhs.name; }
+};
+
+class MindEvaluation : public QObject
+{
+    Q_OBJECT
+
+public:
+    enum AggregationType
+    {
+        NoMerge,  // 数据集结
+        Merge     // 矩阵集结
+    };
+
+    /**
+     * @brief MindEvaluation
+     * @param mind 脑图管理类
+     * @param expertId 专家id
+     * @param tableType 表属于哪种
+     * @param mindMatrix 是否专家打分
+     * @param parent
+     */
+    MindEvaluation(CMind *mind, int expertId, const QString &tableType, int mindMatrix, QObject *parent = nullptr);
+    MindEvaluation(CMind *mind, AggregationType atype, const QString &tableType, int mindMatrix,
+                   QObject *parent = nullptr);
+    ~MindEvaluation();
+    void updateSeqNodes();
+    void computeWeights();
+
+    QList<MindNodeItem> mindNodeWeights;
+
+private:
+    void init();
+    void computeSingleWeights();   // 单专家
+    void computeNoMergeWeights();  // 数据集结
+    void computeMergeWeights();    // 矩阵集结
+
+    void computeOneEntry(const QList<NodeMatrixInfo *> &nmInfos, QList<MindNodeItem> &mindNodeItem);  // 计算单个实例
+
+private:
+    CMind *m_mind;
+    int m_expertId;
+    QString m_tableType;
+    int m_mindMatrix;
+
+    QList<QList<SeqNode>> m_seqNodes;
+
+    AggregationType m_aggregationType;
+    bool m_isAggregationOp;  // 是否做集结操作
+};
+
+#endif  // MINDEVALUATION_H