Home > INIT > removeLowScoreGenes.m

removeLowScoreGenes

PURPOSE ^

removeLowScoreGenes Remove low-scoring genes from model.

SYNOPSIS ^

function [newModel,remGenes] = removeLowScoreGenes(model,geneScores,isozymeScoring,complexScoring)

DESCRIPTION ^

removeLowScoreGenes  Remove low-scoring genes from model.

   This function removes genes from a model based on their scores, a step
   used by the tINIT package. The function recognizes and differentiates
   between isozymes and subunits of an enzyme complex. Genes are removed
   from each grRule, subject to the following conditions:
       1) At least one gene must remain associated with the reaction
       2) Genes involved in a complex (joined by ANDs) are not removed

 Usage:

   [newModel,remGenes] = removeLowScoreGenes(model,geneScores,complexScoring);

 Inputs:

   model           Model structure from which genes are to be removed.

   geneScores      A vector of scores associated with the model genes.
                   Genes with a positive score will remain in the model,
                   whereas genes with a negative score will try to be
                   removed.
                   
                   If all genes associated with a reaction have a negative
                   score, then the least-negative gene will remain; if 
                   there is a tie, one will be selected at random.

                   If a negative-scoring gene is a subunit in a complex, 
                   it will not be removed; however, the entire complex may
                   be removed. See the following example cases:

                    Original: G1 or (G2 and G3 and G4)
                    Negative: G1, G2
                         New: G2 and G3 and G4

                    Original: G1 or (G2 and G3) or (G4 and G5)
                    Negative: G1, G2
                         New: G4 and G5     [using default complexScoring]

                    Original: (G1 and (G2 or G3) and G4)
                    Negative: G2
                         New: (G1 and G3 and G4)

   isozymeScoring  Method used to combine the scores of multiple isozymes;
                   'min', 'max', 'median', or 'average'. 
                   (optional, default 'max')

   complexScoring  Method used to combine the scores of enzyme complex
                   subunits: 'min', 'max', 'median', or 'average'. 
                   (optional, default 'min')

 Outputs:

   newModel        Model with updated gene, grRules, and rxnGeneMat fields
                   after attemping to remove negative-score genes.

   remGenes        A list of negative-score genes that were fully removed
                   from the model. Negative-score genes that were removed
                   from some grRules but not all will not be included in
                   this list.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [newModel,remGenes] = removeLowScoreGenes(model,geneScores,isozymeScoring,complexScoring)
0002 %removeLowScoreGenes  Remove low-scoring genes from model.
0003 %
0004 %   This function removes genes from a model based on their scores, a step
0005 %   used by the tINIT package. The function recognizes and differentiates
0006 %   between isozymes and subunits of an enzyme complex. Genes are removed
0007 %   from each grRule, subject to the following conditions:
0008 %       1) At least one gene must remain associated with the reaction
0009 %       2) Genes involved in a complex (joined by ANDs) are not removed
0010 %
0011 % Usage:
0012 %
0013 %   [newModel,remGenes] = removeLowScoreGenes(model,geneScores,complexScoring);
0014 %
0015 % Inputs:
0016 %
0017 %   model           Model structure from which genes are to be removed.
0018 %
0019 %   geneScores      A vector of scores associated with the model genes.
0020 %                   Genes with a positive score will remain in the model,
0021 %                   whereas genes with a negative score will try to be
0022 %                   removed.
0023 %
0024 %                   If all genes associated with a reaction have a negative
0025 %                   score, then the least-negative gene will remain; if
0026 %                   there is a tie, one will be selected at random.
0027 %
0028 %                   If a negative-scoring gene is a subunit in a complex,
0029 %                   it will not be removed; however, the entire complex may
0030 %                   be removed. See the following example cases:
0031 %
0032 %                    Original: G1 or (G2 and G3 and G4)
0033 %                    Negative: G1, G2
0034 %                         New: G2 and G3 and G4
0035 %
0036 %                    Original: G1 or (G2 and G3) or (G4 and G5)
0037 %                    Negative: G1, G2
0038 %                         New: G4 and G5     [using default complexScoring]
0039 %
0040 %                    Original: (G1 and (G2 or G3) and G4)
0041 %                    Negative: G2
0042 %                         New: (G1 and G3 and G4)
0043 %
0044 %   isozymeScoring  Method used to combine the scores of multiple isozymes;
0045 %                   'min', 'max', 'median', or 'average'.
0046 %                   (optional, default 'max')
0047 %
0048 %   complexScoring  Method used to combine the scores of enzyme complex
0049 %                   subunits: 'min', 'max', 'median', or 'average'.
0050 %                   (optional, default 'min')
0051 %
0052 % Outputs:
0053 %
0054 %   newModel        Model with updated gene, grRules, and rxnGeneMat fields
0055 %                   after attemping to remove negative-score genes.
0056 %
0057 %   remGenes        A list of negative-score genes that were fully removed
0058 %                   from the model. Negative-score genes that were removed
0059 %                   from some grRules but not all will not be included in
0060 %                   this list.
0061 %
0062 
0063 
0064 if nargin < 3 || isempty(isozymeScoring)
0065     isozymeScoring = 'max';
0066 end
0067 if nargin < 4
0068     complexScoring = 'min';
0069 end
0070 
0071 if ~isequal(size(model.genes),size(geneScores))
0072     error('The dimensions of model genes and geneScores do not match.');
0073 end
0074 
0075 % convert logical operators to symbols
0076 grRules = model.grRules;
0077 if any(contains(grRules,{'&','|'}))
0078     symbolicRules = true;
0079 else
0080     symbolicRules = false;
0081 end
0082 grRules = regexprep(grRules,' and ',' & ');
0083 grRules = regexprep(grRules,' or ',' | ');
0084 
0085 % get unique list of grRules
0086 [uRules,~,rule_ind] = unique(grRules);
0087 
0088 % iterate through each rule
0089 newRules = uRules;  %initialize newRules
0090 for i = 1:numel(uRules)
0091     if isempty(uRules{i}) || ~contains(uRules{i},'|')
0092         continue
0093     elseif contains(uRules{i},'&')
0094         newRules{i} = processComplexRule(uRules{i},model.genes,geneScores,isozymeScoring,complexScoring);
0095     else
0096         newRules{i} = processSimpleRule(uRules{i},model.genes,geneScores,isozymeScoring,complexScoring);
0097     end
0098 end
0099 
0100 % re-map unique rules to model
0101 newModel = model;
0102 newModel.grRules = newRules(rule_ind);
0103 
0104 % restore original logical operator formatting if it was changed
0105 if ~symbolicRules
0106     newModel.grRules = regexprep(newModel.grRules, ' \| ', ' or ');
0107     newModel.grRules = regexprep(newModel.grRules, ' & ', ' and ');
0108 end
0109 
0110 % regenerate "genes" and "rxnGeneMat" model fields
0111 [genes,rxnGeneMat] = getGenesFromGrRules(newModel.grRules);
0112 
0113 % determine which of the original genes were removed
0114 remInd = ~ismember(model.genes,genes);
0115 remGenes = model.genes(remInd);
0116 
0117 % Keep the retained genes in their original order rather than the sorted
0118 % order returned by getGenesFromGrRules. Gene removal never introduces new
0119 % genes, so the remaining genes are model.genes(~remInd). Preserving this
0120 % order ensures the gene-associated fields trimmed below (geneShortNames,
0121 % proteins, etc.), which are indexed by remInd, stay aligned with genes.
0122 newModel.genes = model.genes(~remInd);
0123 [~,reorderInd] = ismember(newModel.genes,genes);
0124 newModel.rxnGeneMat = rxnGeneMat(:,reorderInd);
0125 
0126 if isfield(newModel,'geneShortNames')
0127     newModel.geneShortNames(remInd) = [];
0128 end
0129 if isfield(newModel,'proteins')
0130     newModel.proteins(remInd) = [];
0131 end
0132 if isfield(newModel,'geneMiriams')
0133     newModel.geneMiriams(remInd) = [];
0134 end
0135 if isfield(newModel,'geneFrom')
0136     newModel.geneFrom(remInd) = [];
0137 end
0138 if isfield(newModel,'geneComps')
0139     newModel.geneComps(remInd) = [];
0140 end
0141 
0142 
0143 end
0144 
0145 
0146 
0147 function [updatedRule,rScore] = processSimpleRule(rule,genes,gScores,isozymeScoring,complexScoring)
0148 % Either score or modify a reaction gene rule containig only ANDs or ORs.
0149 %
0150 % If the rule contains an enzyme complex (all ANDs), the complex will be
0151 % scored based on the score of its subunits. Subunits without a score (NaN)
0152 % will be excluded from the score calculation.
0153 %
0154 % If the rule contains only isozymes (all ORs), the negative-score genes
0155 % will be removed from the rule. Isozymes without a score (NaN) will not be
0156 % removed from the rule. The resuling rule will then be scored.
0157 
0158 
0159 % get IDs and indices of genes involved in rule
0160 ruleGenes = unique(regexp(rule,'[^&|\(\) ]+','match'));
0161 [~,geneInd] = ismember(ruleGenes,genes);
0162 
0163 % rules with one or no genes remain unchanged
0164 if numel(ruleGenes) < 2
0165     rScore = gScores(geneInd);
0166     updatedRule = rule;
0167     return
0168 end
0169 
0170 if ~contains(rule,'&')  % rule contains isozymes
0171     
0172     scoreMethod = isozymeScoring;
0173     negInd = gScores(geneInd) < 0;  % NaNs will return false here
0174     if all(negInd)
0175         % get the least negative gene, adding a small random value to avoid a tie
0176         [~,maxInd] = max(gScores(geneInd) + rand(size(geneInd))*(1e-8));
0177         updatedRule = ruleGenes{maxInd};
0178     elseif sum(~negInd) == 1
0179         updatedRule = ruleGenes{~negInd};
0180     else
0181         updatedRule = strjoin(ruleGenes(~negInd),' | ');
0182         if startsWith(rule,'(')
0183             updatedRule = ['(',updatedRule,')'];
0184         end
0185     end
0186     
0187     % update ruleGenes and their indices
0188     ruleGenes = unique(regexp(updatedRule,'[^&|\(\) ]+','match'));
0189     [~,geneInd] = ismember(ruleGenes,genes);
0190     
0191 elseif ~contains(rule,'|')  % rule contains enzyme complex
0192     scoreMethod = complexScoring;
0193     updatedRule = rule;
0194 else
0195     error('This function cannot handle rules with both "OR" and "AND" expressions.');
0196 end
0197 
0198 % score rule
0199 switch lower(scoreMethod)
0200     case 'min'
0201         rScore = min(gScores(geneInd),[],'omitnan');
0202     case 'max'
0203         rScore = max(gScores(geneInd),[],'omitnan');
0204     case 'median'
0205         rScore = median(gScores(geneInd),'omitnan');
0206     case 'average'
0207         rScore = mean(gScores(geneInd),'omitnan');
0208 end
0209 
0210 end
0211 
0212 
0213 
0214 function updatedRule = processComplexRule(rule,genes,gScores,isozymeScoring,complexScoring)
0215 % Update reactions containing both AND and OR expressions.
0216 %
0217 % Negative-score genes will be removed if they are isozymic, whereas they
0218 % will not be removed if they are part of an enzyme complex. However, if
0219 % the enzyme complex has a negative score, the entire complex will be
0220 % removed, as long as it is not the only remaining element in the rule.
0221 
0222 
0223 % Specify phrases to search for in the grRule. These phrases will find
0224 % genes grouped by all ANDs (first phrase) or all ORs (second phrase).
0225 search_phrases = {'\([^&|\(\) ]+( & [^&|\(\) ]+)+\)', '\([^&|\(\) ]+( \| [^&|\(\) ]+)+\)'};
0226 
0227 % initialize some variables
0228 subsets = {};  % subsets are groups of genes grouped by all ANDs or all ORs
0229 c = 1;  % counter to keep track of the group (subset) number
0230 r_orig = rule;  % record original rule to determine when it stops changing
0231 for k = 1:100  % iterate some arbitrarily high number of times
0232     for j = 1:length(search_phrases)
0233         new_subset = regexp(rule,search_phrases{j},'match')';  % extract subsets
0234         if ~isempty(new_subset)
0235             subsets = [subsets; new_subset];  % append to list of subsets
0236             subset_nums = arrayfun(@num2str,(c:length(subsets))','UniformOutput',false);  % get group numbers to be assigned to the new subsets, and convert to strings
0237             rule = regexprep(rule,search_phrases{j},strcat('#',subset_nums,'#'),'once');  % replace the subsets in the expression with their group numbers (enclosed by "#"s)
0238             c = c + length(new_subset);
0239         end
0240     end
0241     if isequal(rule,r_orig)
0242         break;  % stop iterating when rule stops changing
0243     else
0244         r_orig = rule;
0245     end
0246 end
0247 subsets{end+1} = rule;  % add final state of rule as the last subset
0248 
0249 % score and update each subset, and append to gene list and gene scores
0250 for i = 1:numel(subsets)
0251     [subsets{i},subset_score] = processSimpleRule(subsets{i},genes,gScores,isozymeScoring,complexScoring);
0252     gScores = [gScores; subset_score];
0253     genes = [genes; {strcat('#',num2str(i),'#')}];
0254 end
0255 
0256 % reconstruct the rule from its updated subsets
0257 updatedRule = subsets{end};
0258 for i = c-1:-1:1
0259     updatedRule = regexprep(updatedRule,strcat('#',num2str(i),'#'),subsets{i});
0260 end
0261 
0262 end
0263 
0264 
0265

Generated by m2html © 2005