You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++11中随机打乱矩阵行列并保留行列名称的实现问题

解决方案:同步打乱矩阵行列与对应名称

你的核心问题有两个:

  1. 原代码中每行单独随机打乱列元素,导致各行的列顺序不一致,根本无法对应统一的列名称;
  2. 没有将行列名称与矩阵元素的打乱操作同步执行。

下面是修正后的完整代码,实现统一打乱列顺序并同步保留列名称,同时保留行名称与行数据的对应关系:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <random>
#include <algorithm>
#include <numeric>  // 用于std::iota生成连续索引
#include "util/base.hpp"

// 写入带行列名称的矩阵(符合生物信息学常见格式)
void writeMatrixWithNames(const std::vector<std::vector<double>>& matrix, 
                          const std::vector<std::string>& rowNames, 
                          const std::vector<std::string>& colNames, 
                          const std::string& out_file_name) {
    std::ofstream file(out_file_name);
    
    // 写入第一行列名称(首列留空对应行名称列)
    file << "\t";
    for (size_t i = 0; i < colNames.size(); ++i) {
        file << colNames[i];
        if (i != colNames.size() - 1) file << "\t";
    }
    file << "\n";
    
    // 逐行写入行名称+对应数据
    for (size_t rowIdx = 0; rowIdx < matrix.size(); ++rowIdx) {
        file << rowNames[rowIdx] << "\t";
        const auto& row = matrix[rowIdx];
        for (size_t i = 0; i < row.size(); ++i) {
            file << row[i];
            if (i != row.size() - 1) file << "\t";
        }
        file << "\n";
    }
    file.close();
}

// 同步打乱矩阵列顺序与列名称
void permuteMatrixColumns(std::vector<std::vector<double>>& matrix, 
                          std::vector<std::string>& colNames, 
                          std::mt19937& g) {
    // 生成列索引序列并打乱
    std::vector<size_t> colIndices(colNames.size());
    std::iota(colIndices.begin(), colIndices.end(), 0);
    std::shuffle(colIndices.begin(), colIndices.end(), g);
    
    // 重新排列列名称
    std::vector<std::string> newColNames(colNames.size());
    for (size_t i = 0; i < colIndices.size(); ++i) {
        newColNames[i] = colNames[colIndices[i]];
    }
    colNames.swap(newColNames);
    
    // 按同一索引排列所有行的元素,保证列对应关系一致
    for (auto& row : matrix) {
        std::vector<double> newRow(row.size());
        for (size_t i = 0; i < colIndices.size(); ++i) {
            newRow[i] = row[colIndices[i]];
        }
        row.swap(newRow);
    }
}

// 可选:同步打乱矩阵行顺序与行名称
void permuteMatrixRows(std::vector<std::vector<double>>& matrix, 
                       std::vector<std::string>& rowNames, 
                       std::mt19937& g) {
    std::vector<size_t> rowIndices(rowNames.size());
    std::iota(rowIndices.begin(), rowIndices.end(), 0);
    std::shuffle(rowIndices.begin(), rowIndices.end(), g);
    
    // 重新排列行名称
    std::vector<std::string> newRowNames(rowNames.size());
    for (size_t i = 0; i < rowIndices.size(); ++i) {
        newRowNames[i] = rowNames[rowIndices[i]];
    }
    rowNames.swap(newRowNames);
    
    // 重新排列矩阵行
    std::vector<std::vector<double>> newMatrix(matrix.size());
    for (size_t i = 0; i < rowIndices.size(); ++i) {
        newMatrix[i] = std::move(matrix[rowIndices[i]]);
    }
    matrix.swap(newMatrix);
}

int main(int argc, char* argv[]) {
    if (argc < 5) {
        std::cerr << "Usage: " << argv[0] << " <input file> <output file base> <number of permutations> <seed>\n";
        return 1;
    }

    std::string inputFile = argv[1];
    std::string outputFileBase = argv[2];
    int numPermutations = std::stoi(argv[3]);
    int seed = std::stoi(argv[4]);
    
    std::vector<std::string> colAnnotations; // 列名称/注释
    std::vector<std::string> geneNames;      // 行名称(基因名)
    std::vector<std::vector<double>> matrix;
    load(inputFile, colAnnotations, geneNames, matrix);

    std::mt19937 g(seed);

    for (int i = 0; i < numPermutations; ++i) {
        auto permutedMatrix = matrix;
        auto permutedColNames = colAnnotations;
        auto permutedRowNames = geneNames; // 若要打乱行,需复制行名称
        
        // 执行列打乱(核心需求)
        permuteMatrixColumns(permutedMatrix, permutedColNames, g);
        
        // 若需要同时打乱行,取消下面注释
        // permuteMatrixRows(permutedMatrix, permutedRowNames, g);
        
        std::string out_file_name = outputFileBase + "_permutation" + std::to_string(i + 1) + ".txt";
        writeMatrixWithNames(permutedMatrix, permutedRowNames, permutedColNames, out_file_name);
    }

    return 0;
}

关键说明

  • 统一列打乱:生成一次列索引的随机排列,所有行都按此排列调整元素,确保列名称与列数据的对应关系始终一致;
  • 行列名称同步:在打乱矩阵元素的同时,对名称向量执行完全相同的索引重排;
  • 可选行打乱:如果需要同时打乱行顺序,取消permuteMatrixRows的调用注释即可,逻辑与列打乱完全一致;
  • 标准化输出:新的写入函数生成带表头和行名的矩阵格式,适配后续Pearson/Spearman相关性分析的输入要求。

内容的提问来源于stack exchange,提问作者zerberus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 02:09:51