halfway merged and pulled?!
This commit is contained in:
68
Classes/DataBaseHandler/Equalizerstruct.m
Normal file
68
Classes/DataBaseHandler/Equalizerstruct.m
Normal file
@@ -0,0 +1,68 @@
|
||||
classdef Equalizerstruct
|
||||
% Equalizerstruct - Class to store and manage equalizer structure data
|
||||
|
||||
properties
|
||||
eq_id (1,1) double {mustBeNumeric} = NaN
|
||||
equalizer_structure equalizer_structure = equalizer_structure.ffe
|
||||
eq
|
||||
mlse
|
||||
comment char = string.empty() % Changed to string with proper empty initialization
|
||||
hash char = string.empty() % Changed to string with proper empty initialization
|
||||
end
|
||||
|
||||
methods
|
||||
function obj = Equalizerstruct(varargin)
|
||||
% Constructor method for Equalizerstruct
|
||||
% Can be called empty or with name-value pairs
|
||||
|
||||
if nargin > 0
|
||||
for i = 1:2:nargin
|
||||
if isprop(obj, varargin{i})
|
||||
obj.(varargin{i}) = varargin{i+1};
|
||||
else
|
||||
error('Property %s does not exist in Equalizerstruct', varargin{i});
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function s = toStruct(obj)
|
||||
% Convert the object to a struct
|
||||
s = struct();
|
||||
props = properties(obj);
|
||||
for i = 1:length(props)
|
||||
s.(props{i}) = obj.(props{i});
|
||||
end
|
||||
end
|
||||
|
||||
function str = toString(obj)
|
||||
% Convert the object to a formatted string
|
||||
s = obj.toStruct();
|
||||
str = sprintf('Equalizerstruct:\n');
|
||||
fields = fieldnames(s);
|
||||
for i = 1:length(fields)
|
||||
val = s.(fields{i});
|
||||
if isempty(val)
|
||||
str = sprintf('%s%s: []\n', str, fields{i});
|
||||
elseif isnumeric(val) && length(val) > 1
|
||||
str = sprintf('%s%s: [%s]\n', str, fields{i}, num2str(val'));
|
||||
else
|
||||
str = sprintf('%s%s: %s\n', str, fields{i}, string(val));
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
methods (Static)
|
||||
function obj = fromStruct(s)
|
||||
% Create an Equalizerstruct object from a struct
|
||||
obj = Equalizerstruct();
|
||||
fields = fieldnames(s);
|
||||
for i = 1:length(fields)
|
||||
if isprop(obj, fields{i})
|
||||
obj.(fields{i}) = s.(fields{i});
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
147
Classes/DataBaseHandler/Metricstruct.m
Normal file
147
Classes/DataBaseHandler/Metricstruct.m
Normal file
@@ -0,0 +1,147 @@
|
||||
classdef Metricstruct
|
||||
% ResultData - Class to store and manage metric data from signal processing results
|
||||
|
||||
properties
|
||||
result_id (1,1) double {mustBeNumeric} = NaN
|
||||
run_id (1,1) double {mustBeNumeric} = NaN
|
||||
eqParam_id (1,1) double {mustBeNumeric} = NaN
|
||||
date_of_processing (1,1) datetime = datetime('now')
|
||||
|
||||
numBits (1,1) double {mustBeInteger, mustBeNonnegative} = 0
|
||||
BER (1,1) double {mustBeNumeric, mustBeNonnegative, mustBeLessThanOrEqual(BER,1)} = 0
|
||||
numBitErr (1,1) double {mustBeInteger, mustBeNonnegative} = 0
|
||||
BER_precoded (1,1) double {mustBeNumeric, mustBeNonnegative, mustBeLessThanOrEqual(BER_precoded,1)} = 0
|
||||
numBitErr_precoded (1,1) double {mustBeInteger, mustBeNonnegative} = 0
|
||||
|
||||
SNR (1,1) double {mustBeNumeric} = NaN
|
||||
SNR_level (:,1) double {mustBeNumeric} = []
|
||||
STD (1,1) double {mustBeNumeric} = NaN
|
||||
STD_level (:,1) double = []
|
||||
STDrx (1,1) double {mustBeNumeric} = NaN
|
||||
STDrx_level (:,1) double = []
|
||||
EVM (1,1) double {mustBeNumeric} = NaN
|
||||
EVM_level (:,1) double {mustBeNumeric} = []
|
||||
|
||||
GMI (1,1) double {mustBeNumeric} = NaN
|
||||
AIR (1,1) double {mustBeNumeric} = NaN
|
||||
Alpha (:,1) double {mustBeNumeric} = NaN
|
||||
MLSE_dir (:,1) double {mustBeNumeric} = []
|
||||
end
|
||||
|
||||
methods
|
||||
function obj = Metricstruct(varargin)
|
||||
% Constructor method for ResultData
|
||||
% Can be called empty or with name-value pairs
|
||||
|
||||
% Process name-value pairs if provided
|
||||
if nargin > 0
|
||||
for i = 1:2:nargin
|
||||
if isprop(obj, varargin{i})
|
||||
obj.(varargin{i}) = varargin{i+1};
|
||||
else
|
||||
error('Property %s does not exist in ResultData', varargin{i});
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function s = toStruct(obj)
|
||||
% Convert the object to a struct
|
||||
s = struct();
|
||||
props = properties(obj);
|
||||
for i = 1:length(props)
|
||||
s.(props{i}) = obj.(props{i});
|
||||
end
|
||||
end
|
||||
|
||||
function str = toString(obj)
|
||||
% Convert the object to a formatted string
|
||||
s = obj.toStruct();
|
||||
str = sprintf('ResultData:\n');
|
||||
fields = fieldnames(s);
|
||||
for i = 1:length(fields)
|
||||
val = s.(fields{i});
|
||||
if isempty(val)
|
||||
str = sprintf('%s%s: []\n', str, fields{i});
|
||||
elseif isnumeric(val) && length(val) > 1
|
||||
str = sprintf('%s%s: [%s]\n', str, fields{i}, num2str(val'));
|
||||
else
|
||||
str = sprintf('%s%s: %s\n', str, fields{i}, string(val));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function print(obj,options)
|
||||
% Print method to display key metrics in a formatted way
|
||||
arguments
|
||||
obj
|
||||
options.description = '';
|
||||
end
|
||||
|
||||
|
||||
% Define the width for formatting
|
||||
nameWidth = 15; % Width for parameter names
|
||||
valueWidth = 12; % Width for values
|
||||
|
||||
% Print header
|
||||
|
||||
fprintf('\n%s\n', repmat('=', 1, nameWidth + valueWidth));
|
||||
fprintf([char(options.description),' Results \n']);
|
||||
fprintf('%s\n', repmat('=', 1, nameWidth + valueWidth));
|
||||
|
||||
% Function to format numbers with appropriate precision
|
||||
function str = formatNumber(value)
|
||||
if isnan(value)
|
||||
str = 'N/A';
|
||||
elseif abs(value) < 0.1 && value ~= 0
|
||||
str = sprintf('%.2e', value);
|
||||
else
|
||||
str = sprintf('%.4f', value);
|
||||
end
|
||||
end
|
||||
|
||||
% Print each metric
|
||||
% BER metrics
|
||||
fprintf('%-*s: %*s\n', nameWidth, 'BER', valueWidth, formatNumber(obj.BER));
|
||||
fprintf('%-*s: %*s\n', nameWidth, 'BER (precoded)', valueWidth, formatNumber(obj.BER_precoded));
|
||||
|
||||
% SNR
|
||||
fprintf('%-*s: %*s\n', nameWidth, 'SNR', valueWidth, formatNumber(obj.SNR));
|
||||
|
||||
% Information rates
|
||||
fprintf('%-*s: %*s\n', nameWidth, 'GMI', valueWidth, formatNumber(obj.GMI));
|
||||
fprintf('%-*s: %*s GBd \n', nameWidth, 'AIR', valueWidth, formatNumber(obj.AIR.*1e-9));
|
||||
|
||||
% Alpha (if it's not empty, show first few values)
|
||||
if ~isempty(obj.Alpha)
|
||||
if length(obj.Alpha) <= 3
|
||||
alphaStr = sprintf('%.4f ', obj.Alpha);
|
||||
else
|
||||
alphaStr = sprintf('%.4f %.4f %.4f...', obj.Alpha(1:3));
|
||||
end
|
||||
fprintf('%-*s: %s\n', nameWidth, 'Alpha', alphaStr);
|
||||
else
|
||||
fprintf('%-*s: %*s\n', nameWidth, 'Alpha', valueWidth, '[]');
|
||||
end
|
||||
|
||||
% Print footer
|
||||
fprintf('%s\n', repmat('=', 1, nameWidth + valueWidth));
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
methods (Static)
|
||||
|
||||
function obj = fromStruct(s)
|
||||
% Create a ResultData object from a struct
|
||||
obj = Metricstruct();
|
||||
fields = fieldnames(s);
|
||||
for i = 1:length(fields)
|
||||
if isprop(obj, fields{i})
|
||||
obj.(fields{i}) = s.(fields{i});
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
169
Classes/DataBaseHandler/QueryFilter.m
Normal file
169
Classes/DataBaseHandler/QueryFilter.m
Normal file
@@ -0,0 +1,169 @@
|
||||
% QueryFilter - Class for building SQL WHERE conditions for database queries.
|
||||
%
|
||||
% Usage:
|
||||
% qf = QueryFilter();
|
||||
% qf.where('Runs', 'fiber_length', SqlOperator.GREATER_THAN, 5);
|
||||
% qf.where('Runs', 'bitrate', SqlOperator.IN, [224, 336, 448]);
|
||||
% qf.where('Runs', 'is_mpi', SqlOperator.EQUALS, 0);
|
||||
%
|
||||
% % Convert to struct for use in DBHandler or other query functions:
|
||||
% filterStruct = qf.toStruct();
|
||||
%
|
||||
% % Display current filters:
|
||||
% disp(qf);
|
||||
|
||||
classdef QueryFilter < handle
|
||||
|
||||
|
||||
properties (Access = private)
|
||||
filters struct = struct()
|
||||
end
|
||||
|
||||
methods
|
||||
function obj = QueryFilter(oldFormat)
|
||||
% Constructor - optionally convert from old filter format
|
||||
if nargin > 0 && isstruct(oldFormat)
|
||||
tableNames = fieldnames(oldFormat);
|
||||
for t = 1:length(tableNames)
|
||||
tableName = tableNames{t};
|
||||
if isstruct(oldFormat.(tableName))
|
||||
fields = fieldnames(oldFormat.(tableName));
|
||||
for f = 1:length(fields)
|
||||
fieldName = fields{f};
|
||||
value = oldFormat.(tableName).(fieldName);
|
||||
if ~isempty(value)
|
||||
obj.where(tableName, fieldName, value);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function where(obj, tableName, fieldName, operator, value)
|
||||
% Add a WHERE condition to the query
|
||||
%
|
||||
% Inputs:
|
||||
% tableName - Name of the database table (char)
|
||||
% fieldName - Name of the field/column (char)
|
||||
% operator - SqlOperator enum or value if using EQUALS
|
||||
% value - Value to filter by
|
||||
%
|
||||
% Example:
|
||||
% filter.where('Runs', 'fiber_length', SqlOperator.GREATER_THAN, 5)
|
||||
arguments
|
||||
obj
|
||||
tableName char
|
||||
fieldName char
|
||||
operator SqlOperator
|
||||
value = []
|
||||
end
|
||||
|
||||
% Handle case where operator is the value (using default EQUALS)
|
||||
if nargin < 5
|
||||
value = operator;
|
||||
operator = SqlOperator.EQUALS;
|
||||
end
|
||||
|
||||
% Validate operator type
|
||||
if ~isa(operator, 'SqlOperator')
|
||||
error('Operator must be a SqlOperator enumeration');
|
||||
end
|
||||
|
||||
% Validate value based on operator
|
||||
obj.validateValue(operator, value);
|
||||
|
||||
% Create filter
|
||||
filter = SqlFilter(value, operator.toSqlString());
|
||||
|
||||
% Add to filters
|
||||
if ~isfield(obj.filters, tableName)
|
||||
obj.filters.(tableName) = struct();
|
||||
end
|
||||
obj.filters.(tableName).(fieldName) = filter;
|
||||
end
|
||||
|
||||
function s = toStruct(obj)
|
||||
% Convert filters to struct format for database query
|
||||
s = obj.filters;
|
||||
end
|
||||
|
||||
function display(obj)
|
||||
% Custom display of filter conditions
|
||||
fprintf('QueryFilter with conditions:\n');
|
||||
if isempty(fieldnames(obj.filters))
|
||||
fprintf(' No filters set\n');
|
||||
return;
|
||||
end
|
||||
|
||||
tables = fieldnames(obj.filters);
|
||||
for t = 1:length(tables)
|
||||
tableName = tables{t};
|
||||
if ~isempty(fieldnames(obj.filters.(tableName)))
|
||||
fprintf('\nTable: %s\n', tableName);
|
||||
fields = fieldnames(obj.filters.(tableName));
|
||||
for f = 1:length(fields)
|
||||
fieldName = fields{f};
|
||||
filter = obj.filters.(tableName).(fieldName);
|
||||
if isnumeric(filter.value)
|
||||
if length(filter.value) > 1
|
||||
valueStr = ['[', num2str(filter.value), ']'];
|
||||
else
|
||||
valueStr = num2str(filter.value);
|
||||
end
|
||||
elseif isempty(filter.value)
|
||||
valueStr = 'empty';
|
||||
else
|
||||
valueStr = char(filter.value);
|
||||
end
|
||||
fprintf(' %s %s %s\n', fieldName, filter.operator, valueStr);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function clear(obj, tableName)
|
||||
% Clear all filters or filters for a specific table
|
||||
if nargin < 2
|
||||
obj.filters = struct();
|
||||
else
|
||||
if isfield(obj.filters, tableName)
|
||||
obj.filters = rmfield(obj.filters, tableName);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function remove(obj, tableName, fieldName)
|
||||
% Remove a specific filter
|
||||
if isfield(obj.filters, tableName) && ...
|
||||
isfield(obj.filters.(tableName), fieldName)
|
||||
obj.filters.(tableName) = rmfield(obj.filters.(tableName), fieldName);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
methods (Access = private)
|
||||
function validateValue(~, operator, value)
|
||||
% Validate value based on operator type
|
||||
switch operator
|
||||
case SqlOperator.BETWEEN
|
||||
if ~isnumeric(value) || length(value) ~= 2
|
||||
error('BETWEEN operator requires array of 2 numbers');
|
||||
end
|
||||
case SqlOperator.IN
|
||||
if ~isnumeric(value) || isempty(value)
|
||||
error('IN operator requires non-empty array');
|
||||
end
|
||||
case SqlOperator.LIKE
|
||||
if ~ischar(value) && ~isstring(value)
|
||||
error('LIKE operator requires string value');
|
||||
end
|
||||
otherwise
|
||||
% For other operators, just ensure value is not empty
|
||||
if isempty(value)
|
||||
error('Value cannot be empty');
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
22
Classes/DataBaseHandler/SqlFilter.m
Normal file
22
Classes/DataBaseHandler/SqlFilter.m
Normal file
@@ -0,0 +1,22 @@
|
||||
% SqlFilter - Internal class for holding a value and SQL operator for a filter condition.
|
||||
%
|
||||
% Usage:
|
||||
% f = SqlFilter(10, SqlOperator.GREATER_THAN.toSqlString());
|
||||
% % f.value == 10, f.operator == '>'
|
||||
|
||||
|
||||
classdef SqlFilter
|
||||
properties
|
||||
value
|
||||
operator char = '='
|
||||
end
|
||||
|
||||
methods
|
||||
function obj = SqlFilter(value, operator)
|
||||
obj.value = value;
|
||||
if nargin > 1
|
||||
obj.operator = operator;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
48
Classes/DataBaseHandler/SqlOperator.m
Normal file
48
Classes/DataBaseHandler/SqlOperator.m
Normal file
@@ -0,0 +1,48 @@
|
||||
% SqlOperator - Enumeration of supported SQL operators for query building.
|
||||
%
|
||||
% Usage:
|
||||
% op = SqlOperator.GREATER_THAN;
|
||||
% opStr = op.toSqlString(); % returns '>'
|
||||
%
|
||||
% Supported operators:
|
||||
% EQUALS, GREATER_THAN, LESS_THAN, GREATER_EQUAL, LESS_EQUAL,
|
||||
% NOT_EQUAL, IN, BETWEEN, LIKE
|
||||
|
||||
classdef SqlOperator < uint32
|
||||
enumeration
|
||||
EQUALS (1) % ==
|
||||
GREATER_THAN (2) % >
|
||||
LESS_THAN (3) % <
|
||||
GREATER_EQUAL (4) % >=
|
||||
LESS_EQUAL (5) % <=
|
||||
NOT_EQUAL (6) % !=
|
||||
IN (7) % IN
|
||||
BETWEEN (8) % BETWEEN
|
||||
LIKE (9) % LIKE
|
||||
end
|
||||
|
||||
methods
|
||||
function op = toSqlString(obj)
|
||||
switch obj
|
||||
case SqlOperator.EQUALS
|
||||
op = '=';
|
||||
case SqlOperator.GREATER_THAN
|
||||
op = '>';
|
||||
case SqlOperator.LESS_THAN
|
||||
op = '<';
|
||||
case SqlOperator.GREATER_EQUAL
|
||||
op = '>=';
|
||||
case SqlOperator.LESS_EQUAL
|
||||
op = '<=';
|
||||
case SqlOperator.NOT_EQUAL
|
||||
op = '!=';
|
||||
case SqlOperator.IN
|
||||
op = 'IN';
|
||||
case SqlOperator.BETWEEN
|
||||
op = 'BETWEEN';
|
||||
case SqlOperator.LIKE
|
||||
op = 'LIKE';
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
32
Classes/DataBaseHandler/related functions/cleanUpTable.m
Normal file
32
Classes/DataBaseHandler/related functions/cleanUpTable.m
Normal file
@@ -0,0 +1,32 @@
|
||||
function cleanedTable = cleanUpTable(inputTable)
|
||||
% Converts string numbers to numeric, 'NaN' to NaN, and tries to convert date strings to datetime.
|
||||
|
||||
cleanedTable = inputTable;
|
||||
varNames = cleanedTable.Properties.VariableNames;
|
||||
|
||||
for i = 1:numel(varNames)
|
||||
col = cleanedTable.(varNames{i});
|
||||
if iscell(col)
|
||||
numericCol = str2double(col);
|
||||
if all(isnan(numericCol) == strcmpi(col, 'NaN') | cellfun(@isempty, col))
|
||||
cleanedTable.(varNames{i}) = numericCol;
|
||||
else
|
||||
try
|
||||
cleanedTable.(varNames{i}) = datetime(col, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS');
|
||||
catch
|
||||
cleanedTable.(varNames{i}) = string(col);
|
||||
end
|
||||
end
|
||||
elseif isstring(col)
|
||||
numericCol = str2double(col);
|
||||
if all(isnan(numericCol) == strcmpi(col, "NaN"))
|
||||
cleanedTable.(varNames{i}) = numericCol;
|
||||
else
|
||||
try
|
||||
cleanedTable.(varNames{i}) = datetime(col, 'InputFormat', 'yyyy-MM-dd HH:mm:ss');
|
||||
catch
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
53
Classes/DataBaseHandler/related functions/groupIt.m
Normal file
53
Classes/DataBaseHandler/related functions/groupIt.m
Normal file
@@ -0,0 +1,53 @@
|
||||
function resultTable = groupIt(fixedVars, dataTable, aggregationFunction)
|
||||
% groupIt Groups data in a table based on fixedVars and applies aggregationFunction to numeric data.
|
||||
%
|
||||
% resultTable = groupIt(fixedVars, dataTable, aggregationFunction)
|
||||
%
|
||||
% Inputs:
|
||||
% fixedVars - Cell array of variable names to group by
|
||||
% dataTable - Input MATLAB table
|
||||
% aggregationFunction - Function handle (e.g., @mean, @min, @max)
|
||||
%
|
||||
% Output:
|
||||
% resultTable - Grouped and aggregated table
|
||||
|
||||
[G, groupKeys] = findgroups(dataTable(:, fixedVars));
|
||||
varNames = dataTable.Properties.VariableNames;
|
||||
nVars = numel(varNames);
|
||||
aggData = cell(height(groupKeys), nVars);
|
||||
groupCount = zeros(height(groupKeys), 1);
|
||||
|
||||
for i = 1:height(groupKeys)
|
||||
idx = (G == i);
|
||||
groupCount(i) = sum(idx);
|
||||
for j = 1:nVars
|
||||
colData = dataTable.(varNames{j});
|
||||
if isnumeric(colData)
|
||||
if any(idx)
|
||||
aggData{i, j} = aggregationFunction(colData(idx));
|
||||
else
|
||||
aggData{i, j} = NaN;
|
||||
end
|
||||
else
|
||||
if iscell(colData)
|
||||
nonEmptyIdx = find(idx & ~cellfun(@isempty, colData), 1);
|
||||
if ~isempty(nonEmptyIdx)
|
||||
aggData{i, j} = colData{nonEmptyIdx};
|
||||
else
|
||||
aggData{i, j} = [];
|
||||
end
|
||||
else
|
||||
nonEmptyIdx = find(idx, 1);
|
||||
if ~isempty(nonEmptyIdx)
|
||||
aggData{i, j} = colData(nonEmptyIdx);
|
||||
else
|
||||
aggData{i, j} = [];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
resultTable = cell2table(aggData, 'VariableNames', varNames);
|
||||
resultTable.nRows = groupCount;
|
||||
end
|
||||
@@ -0,0 +1,61 @@
|
||||
function [cleanedTable, outliersTable] = removeGroupOutliers(dataTable, fixedVars, y_var)
|
||||
% removeGroupOutliers removes outliers in y_var within each group defined by fixedVars.
|
||||
%
|
||||
% [cleanedTable, outliersTable] = removeGroupOutliers(dataTable, fixedVars, y_var)
|
||||
%
|
||||
% Inputs:
|
||||
% dataTable - Input MATLAB table
|
||||
% fixedVars - Cell array of variable names to group by
|
||||
% y_var - Name of the variable to check for outliers (string or char)
|
||||
%
|
||||
% Outputs:
|
||||
% cleanedTable - Table with outliers removed
|
||||
% outliersTable - Table of removed outlier rows
|
||||
|
||||
[G, groupKeys] = findgroups(dataTable(:, fixedVars));
|
||||
keepIdx = true(height(dataTable), 1);
|
||||
outlierRecords = [];
|
||||
|
||||
for groupIdx = 1:height(groupKeys)
|
||||
groupRows = (G == groupIdx);
|
||||
y_values = dataTable.(y_var)(groupRows);
|
||||
|
||||
% Skip groups with fewer than 3 points
|
||||
if sum(groupRows) < 3
|
||||
continue;
|
||||
end
|
||||
|
||||
% Detect outliers in log10 space (robust for BER, etc.)
|
||||
y_log = log10(y_values);
|
||||
outlierMask = isoutlier(y_log, 'quartiles', 1);
|
||||
|
||||
if any(outlierMask)
|
||||
groupData = dataTable(groupRows, :);
|
||||
outlierGroupTable = groupData(outlierMask, :);
|
||||
|
||||
% Optionally, add group key values for traceability
|
||||
for k = 1:numel(fixedVars)
|
||||
outlierGroupTable.(['Group_', fixedVars{k}]) = repmat(groupKeys{groupIdx, k}, height(outlierGroupTable), 1);
|
||||
end
|
||||
|
||||
outlierRecords = [outlierRecords; outlierGroupTable]; %#ok<AGROW>
|
||||
end
|
||||
|
||||
% Mark outliers for removal
|
||||
groupRowIdx = find(groupRows);
|
||||
keepIdx(groupRowIdx(outlierMask)) = false;
|
||||
end
|
||||
|
||||
cleanedTable = dataTable(keepIdx, :);
|
||||
|
||||
if isempty(outlierRecords)
|
||||
outliersTable = table();
|
||||
else
|
||||
outliersTable = outlierRecords;
|
||||
end
|
||||
|
||||
nRemoved = sum(~keepIdx);
|
||||
nTotalOriginal = height(dataTable);
|
||||
fprintf('Removed %d outliers from the data table (%.2f%% of total %d entries).\n', ...
|
||||
nRemoved, 100*nRemoved/nTotalOriginal, nTotalOriginal);
|
||||
end
|
||||
Reference in New Issue
Block a user