gusucode.com > datatypes 工具箱matlab源码程序 > datatypes/@table/table.m

    classdef (Sealed) table < tabular
%TABLE Table.
%   Tables are used to collect heterogeneous data and metadata into a single
%   container.  Tables are suitable for storing column-oriented or tabular data
%   that are often stored as columns in a text file or in a spreadsheet.  Tables
%   can accommodate variables of different types, sizes, units, etc.  They are
%   often used to store experimental data, with rows representing different
%   observations and columns representing different measured variables.
%
%   Use the TABLE constructor to create a table from variables in the MATLAB
%   workspace.  Use the readtable function to create a table by reading data
%   from a text or spreadsheet file.
%
%   Tables can be subscripted using parentheses much like ordinary numeric
%   arrays, but in addition to numeric and logical indices, you can use a
%   table's variable and row names as indices.  You can access individual
%   variables in a table much like fields in a structure, using dot
%   subscripting.  You can access the contents of one or more variables using
%   brace subscripting.
%
%   Tables can contain different kinds of variables, including numeric, logical,
%   character, categorical, and cell.  However, a table is a different class
%   than the variables that it contains.  For example, even a table that
%   contains only variables that are double arrays cannot be operated on as if
%   it were itself a double array.  However, using dot subscripting, you can
%   operate on a variable in a table as if it were a workspace variable.  Using
%   brace subscripting, you can operate on one or more variables in a table as
%   if they were in a homogeneous array.
%
%   A table T has properties that store metadata such as its variable and row
%   names.  Access or assign to a property using P = T.Properties.PropName or
%   T.Properties.PropName = P, where PropName is one of the following:
%
%   TABLE metadata properties:
%       Description          - A character vector describing the table
%       DimensionNames       - A two-element cell array of character vectors containing names of
%                              the dimensions of the table
%       VariableNames        - A cell array containing names of the variables in the table
%       VariableDescriptions - A cell array of character vectors containing descriptions of the
%                              variables in the table
%       VariableUnits        - A cell array of character vectors containing units for the variables
%                              in table
%       RowNames             - A cell array of nonempty, distinct character vectors containing names
%                              of the rows in the table
%       UserData             - A variable containing any additional information associated
%                              with the table.  You can assign any value to this property.
%
%   TABLE methods and functions:
%     Construction and conversion:
%       table              - Create a table from workspace variables.
%       array2table        - Convert homogeneous array to table.
%       cell2table         - Convert cell array to table.
%       struct2table       - Convert structure array to table.
%       table2array        - Convert table to a homogeneous array.
%       table2cell         - Convert table to cell array.
%       table2struct       - Convert table to structure array.
%     Import and export:
%       readtable          - Create a table by reading from a file.
%       writetable         - Write a table to a file.
%       write              - Write a table to a file.
%     Size and shape:
%       istable            - True for tables.
%       size               - Size of a table.
%       width              - Number of variables in a table.
%       height             - Number of rows in a table.
%       ndims              - Number of dimensions of a table.
%       numel              - Number of elements in a table.
%       horzcat            - Horizontal concatenation for tables.
%       vertcat            - Vertical concatenation for tables.
%     Set membership:
%       intersect          - Find rows common to two tables.
%       ismember           - Find rows in one table that occur in another table.
%       setdiff            - Find rows that occur in one table but not in another.
%       setxor             - Find rows that occur in one or the other of two tables, but not both.
%       unique             - Find unique rows in a table.
%       union              - Find rows that occur in either of two tables.
%       join               - Merge two tables by matching up rows using key variables.
%       innerjoin          - Inner join between two tables.
%       outerjoin          - Outer join between two tables.
%     Data organization:
%       summary            - Print summary of a table.
%       sortrows           - Sort rows of a table.
%       stack              - Stack up data from multiple variables into a single variable.
%       unstack            - Unstack data from a single variable into multiple variables.
%       ismissing          - Find elements in a table that contain missing values.
%       standardizeMissing - Insert missing data indicators into a table.
%     Computations on tables:
%       varfun             - Apply a function to variables in a table.
%       rowfun             - Apply a function to rows of a table.
%
%   Examples:
%
%      % Create a table from individual workspace variables.
%      load patients
%      patients = table(LastName,Gender,Age,Height,Weight,Smoker,Systolic,Diastolic)
%
%      % Select the rows for patients who smoke, and a subset of the variables.
%      smokers = patients(patients.Smoker == true, {'LastName' 'Gender' 'Systolic' 'Diastolic'})
%
%      % Convert the two blood pressure variables into a single variable.
%      patients.BloodPressure = [patients.Systolic patients.Diastolic];
%      patients(:,{'Systolic' 'Diastolic'}) = []
%
%      % Pick out two specific patients by the LastName variable.
%      patients(ismember(patients.LastName,{'Smith' 'Jones'}), :)
%
%      % Convert the LastName variable into row names.
%      patients.Properties.RowNames = patients.LastName;
%      patients.LastName = []
%
%      % Use the row names to pick out two specific patients.
%      patients({'Smith' 'Jones'},:)
%
%      % Add metadata to the table.
%      patients.Properties.Description = 'Simulated patient data';
%      patients.Properties.VariableUnits =  {''  'Yrs'  'In'  'Lbs'  ''  'mm Hg'};
%      patients.Properties.VariableDescriptions{6} = 'Systolic/Diastolic';
%      summary(patients)
%
%      % Create a new variable in the table from existing variables.
%      patients.BMI = (patients.Weight * 0.453592) ./ (patients.Height * 0.0254).^2
%      patients.Properties.VariableUnits{'BMI'} =  'kg/m^2';
%      patients.Properties.VariableDescriptions{'BMI'} = 'Body Mass Index';
%
%      % Sort the table based on the new variable.
%      sortrows(patients,'BMI')
%
%      % Make a scatter plot of two of the table's variables.
%      plot(patients.Height,patients.Weight,'o')
%
%      % Create tables from text and spreadsheet files
%      patients2 = readtable('patients.dat','ReadRowNames',true)
%      patients3 = readtable('patients.xls','ReadRowNames',true)
%
%      % Create a table from a numeric matrix
%      load tetmesh.mat
%      t = array2table(X,'VariableNames',{'x' 'y' 'z'});
%      plot3(t.x,t.y,t.z,'.')
%
%   See also TABLE, CATEGORICAL

%   Copyright 2012-2016 The MathWorks, Inc.

    properties(Constant, Access='protected')
        % Constant properties are not persisted when serialized
        version = 2.0;
        propertyNames = [fieldnames(tabular.arrayPropsDflts); ...
                         matlab.internal.table.tableMetaDim.propertyNames; ...
                         matlab.internal.table.tableVarNamesDim.propertyNames; ...
                         matlab.internal.table.tableRowNamesDim.propertyNames];
        defaultDimNames = matlab.internal.table.dfltDimNames;
    end
    
    properties(Access='protected')
        % * DO NOT MODIFY THIS LIST OF NON-TRANSIENT INSTANCE PROPERTIES *
        % Declare any additional properties in the Transient block below,
        % and add proper logic in saveobj/loadobj to handle persistence
        data = cell(1,0);
    end
    
    properties(Transient, Access='protected')
        % Create the metaDim to not display the row labels header, and with dim names
        % backwards compatibility turned on
        metaDim = matlab.internal.table.tableMetaDim(2,table.defaultDimNames,false,true);
        rowDim = matlab.internal.table.tableRowNamesDim(0);
        varDim = matlab.internal.table.tableVarNamesDim(0);
        
        % 'Properties' will appear to contain this, as well as the per-row, per-var,
        % and per-dimension properties contained in rowDim, varDim. and metaDim,
        arrayProps = tabular.arrayPropsDflts;
    end
        
    methods
        function t = table(varargin)
        %TABLE Create a table from workspace variables.
        %   T = TABLE(VAR1, VAR2, ...) creates a table T from the workspace
        %   variables VAR1, VAR2, ... .  All variables must have the same number
        %   of rows.
        %
        %   T = TABLE(..., 'VariableNames', {'name1', ..., 'name_M'}) creates a
        %   table containing variables that have the specified variable names.
        %   The names must be valid MATLAB identifiers, and unique.
        %
        %   T = TABLE(..., 'RowNames', {'name1', ..., 'name_N'}) creates a table
        %   that has the specified row names.  The names need not be valid MATLAB
        %   identifiers, but must be unique.
        %
        %   Tables can contain variables that are built-in types, or objects that
        %   are arrays and support standard MATLAB parenthesis indexing of the form
        %   var(i,...), where i is a numeric or logical vector that corresponds to
        %   rows of the variable.  In addition, the array must implement a SIZE method
        %   with a DIM argument, and a VERTCAT method.
        %
        %
        %   Examples:
        %      % Create a table from individual workspace variables.
        %      load patients
        %      patients = table(LastName,Gender,Age,Height,Weight,Smoker,Systolic,Diastolic)
        %      patients.Properties.Description = 'Simulated patient data';
        %      patients.Properties.VariableUnits =  {''  ''  'Yrs'  'In'  'Lbs'  ''  'mm Hg'  'mm Hg'};
        %
        %   See also READTABLE, CELL2TABLE, ARRAY2TABLE, STRUCT2TABLE.
        
            if nargin == 0
                % Nothing to do
            else
                % Construct from separate variables
                [numVars,numRows] = tabular.countVarInputs(varargin);
                vars = varargin(1:numVars);
                
                if numVars < nargin
                    pnames = {'VariableNames'  'RowNames' };
                    dflts =  {            []          []  };
                    try
                        [varnames,rownames,supplied] ...
                            = matlab.internal.table.parseArgs(pnames, dflts, varargin{numVars+1:end});
                    catch ME
                        % The inputs included a 1xM string that was interpreted as a param name,
                        % but something went wrong. If all of the preceedng inputs had one row,
                        % or if that string was first, these two errors suggest that the string
                        % was intended as data. Suggest alternative options, in that case.
                        if (numVars == 0 || numRows == 1)
                            if strcmp(ME.identifier,'MATLAB:table:parseArgs:BadParamName') || ...
                                    strcmp(ME.identifier,'MATLAB:table:parseArgs:WrongNumberArgs')
                                cause = message('MATLAB:table:ConstructingFromStrings');
                                ME = addCause(ME,MException(cause.Identifier,'%s',getString(cause)));
                            end
                        end
                        throw(ME);
                    end
                else
                    supplied.VariableNames = false;
                    supplied.RowNames = false;
                end
                
                if supplied.RowNames
                    if numVars == 0, numRows = length(rownames); end
                else
                    rownames = {};
                end
                
                if ~supplied.VariableNames
                    % Get the workspace names of the input arguments from inputname
                    varnames = repmat({''},1,numVars);
                    for i = 1:numVars, varnames{i} = inputname(i); end
                    % Fill in default names for data args where inputname couldn't
                    empties = cellfun('isempty',varnames);
                    if any(empties)
                        varnames(empties) = matlab.internal.table.dfltVarNames(find(empties)); %#ok<FNDSB>
                    end
                    % Make sure default names or names from inputname don't conflict
                    varnames = matlab.lang.makeUniqueStrings(varnames,{},namelengthmax);
                end
                
                t.rowDim = matlab.internal.table.tableRowNamesDim(numRows,rownames);
                t.varDim = matlab.internal.table.tableVarNamesDim(numVars,varnames); % error if invalid, duplicate, or empty
                t.data = vars;
                
                % Detect conflicts between the var names and the default dim names.
                t.metaDim = t.metaDim.checkAgainstVarLabels(varnames);
            end
        end % table constructor
    end % methods block
    
    methods(Hidden) % hidden methods block
        write(t,filename,varargin)
    end
            
    methods(Hidden, Static)
        % This function is for internal use only and will change in a
        % future release.  Do not use this function.
        t = readFromFile(filename,args)
        
        function t = empty(varargin)
        %EMPTY Create an empty table.
        %   T = TABLE.EMPTY() creates a 0x0 table.
        %
        %   T = TABLE.EMPTY(NROWS,NVARS) or T = TABLE.EMPTY([NROWS NVARS]) creates an
        %   NROWSxNVARS table.  At least one of NROWS or NVARS must be zero.
        %
        %   See also TABLE, ISEMPTY.
            if nargin == 0
                t = table();
            else
                sizeOut = size(zeros(varargin{:}));
                if prod(sizeOut) ~= 0
                    error(message('MATLAB:table:empty:EmptyMustBeZero'));
                elseif length(sizeOut) > 2
                    error(message('MATLAB:table:empty:EmptyMustBeTwoDims'));
                else
                    % Create a 0x0 table, and then resize to the correct number
                    % of rows or variables.
                    t = table();
                    if sizeOut(1) > 0
                        t.rowDim = t.rowDim.lengthenTo(sizeOut(1));
                    end
                    if sizeOut(2) > 0
                        t.varDim = t.varDim.lengthenTo(sizeOut(2));
                        t.data = cell(1,sizeOut(2)); % assume double
                    end
                end
            end
        end
        
        % Called by cell2table, struct2table
        function t = fromScalarStruct(s)
            % This function is for internal use only and will change in a
            % future release.  Do not use this function.
            
            % Construct a table from a scalar struct
            vnames = fieldnames(s);
            p = length(vnames);
            if p > 0
                n = unique(structfun(@(f)size(f,1),s));
                if ~isscalar(n)
                    error(message('MATLAB:table:UnequalFieldLengths'));
                end
            else
                n = 0;
            end
            t = table();
            t.data = struct2cell(s)';
            t.rowDim = matlab.internal.table.tableRowNamesDim(n);
            t.varDim = matlab.internal.table.tableVarNamesDim(p,vnames);
        end
    end % hidden static methods block
        
    methods(Access = 'protected')
        function b = cloneAsEmpty(a)
            %CLONEASEMPTY Create a new empty table from an existing one.
%             if strcmp(class(a),'table') %#ok<STISA>
                b = table();
%             else % b is a subclass of table
%                 b = a; % respect the subclass
%                 % leave b.metaDim alone
%                 b.rowDim = matlab.internal.table.tableRowNamesDim();
%                 b.varDim = matlab.internal.table.tableVarNamesDim();
%                 b.data = cell(1,0);
%                 leave b.arrayProps alone
%             end
        end
        
        function errID = throwSubclassSpecificError(obj,msgid,varargin)
            % Throw the table version of the msgid error, using varargin as the
            % variables to fill the holes in the message.
            errID = throwSubclassSpecificError@tabular(obj,['table:' msgid],varargin{:});
            if nargout == 0
                throwAsCaller(errID);
            end
        end
    end
    
    methods(Access = 'protected', Static)
        t = readTextFile(file,args)
        t = readXLSFile(xlsfile,args)
    end
    
    %%%%% PERSISTENCE BLOCK ensures correct save/load across releases %%%%%
    %%%%% Properties and methods in this block maintain the exact class %%%
    %%%%% schema required for TABLE to persist through MATLAB releases %%%%
    properties(Access='private')
        % ** DO NOT EDIT THIS LIST OR USE THESE PROPERTIES INSIDE TABLE **
        % These properties mirror the pre-R2016b internal representation, which was also
        % the external representation saved to mat files. Post-R2016b saveobj and loadobj
        % continue to use them as the external representation for save/load compatibility
        % with earlier releases.
        ndims;
        nrows;
        rownames;
        nvars;
        varnames;
        props;
    end
    
    methods(Hidden)
        function tsave = saveobj(t)
            % this saveobj is designed for 2D table only
            assert(t.metaDim.length==2);
            
            tsave = t;
            
            % The .data property is not transient, it will always be be saved. The other
            % (metadata) properties are transient, their values are saved by copying to
            % the corresponding (non-transient) properties of the external representation.
            tsave.ndims = t.metaDim.length;
            tsave.nrows = t.rowDim.length;
            tsave.nvars = t.varDim.length;
            tsave.rownames = t.rowDim.labels;
            tsave.varnames = t.varDim.labels;
            
            % .props is a scalar struct to contain any remaining metadata. At load time,
            % table ignores any field it does not recognize.
            tsave.props.Description = t.arrayProps.Description;
            tsave.props.UserData = t.arrayProps.UserData;
            tsave.props.VariableDescriptions = t.varDim.descrs;
            tsave.props.VariableUnits = t.varDim.units;
            tsave.props.DimensionNames = t.metaDim.labels;
            tsave.props = orderfields(tsave.props,... % guarantee the field order
                                     {'Description',...
                                      'UserData', ...
                                      'VariableDescriptions', ...
                                      'VariableUnits', ...
                                      'DimensionNames'});
            
            % Additional data that needs to be persisted shall be packaged
            % and attached to tsave.props as one of its fields, such as:
            %
            %     tsave.props.serializedObj
            %
            % Also add corresponding deserialization logic in loadobj below
            tsave.props.VersionSavedFrom = t.version;
        end
    end
    
    methods(Hidden, Static)
        function t = loadobj(s)
            noRowLabelsHeaderDisp = false;
            backCompatForDimNames = true;
            % s might be a table, or it might be a scalar struct. In either case, copy its
            % data into an empty table, then copy its metadata from the external
            % representation into the current class schema.
            t = table();
            t.data = s.data;
            % Pre-R2016b tables (i.e. no 'VersionSavedFrom' field) might have DimensionNames
            % that do not satisfy current requirements to support new dot subscripting
            % functionality added in R2016b. To allow loading such existing tables, modify
            % any invalid names and warn. See tableMetaDim class for details. This is only
            % an issue for tables saved pre-2016b, newer versions with out-of-model
            % DimensionNames could not have been created to begin with. Even for pre-2016b,
            % the defaults met those requirements so the names would have had to have been
            % set explicitly.
            dimNames = s.props.DimensionNames;
            s.props = rmfield(s.props,'DimensionNames');
            if ~isfield(s.props,'VersionSavedFrom') % pre-R2016b tables
                if strcmp(dimNames(2),'Variable')
                    % If the second dim name is the old default, assume it has never been changed,
                    % probably never even looked at, and update it to the current default to make it
                    % consistent with the new design. Otherwise, leave it alone.
                    dimNames(2) = t.defaultDimNames(2);
                end
                t.metaDim = matlab.internal.table.tableMetaDim(2,dimNames,noRowLabelsHeaderDisp,backCompatForDimNames);
                t.metaDim = t.metaDim.checkAgainstVarLabels(s.varnames);
            else % R2016b-on tables or timetables
                t.metaDim = matlab.internal.table.tableMetaDim(s.ndims,dimNames,noRowLabelsHeaderDisp,backCompatForDimNames);
            end
            t.varDim  = matlab.internal.table.tableVarNamesDim(s.nvars, s.varnames);
            % Pre-R2016b, a 0x0 cell for rownames implicitly indicated no row names, while a 0x1
            % indicated a 0xN table _with_ row names. R2016b-on use rowDim.hasLabels explicitly,
            % which gets set correctly here as false and true, respectively, in those two cases.
            t.rowDim = matlab.internal.table.tableRowNamesDim(s.nrows, s.rownames);
            
            % Remove any fields in .props that are not recognized in the current version.
            toRemove = setdiff(fieldnames(s.props),t.propertyNames);
            if ~isempty(toRemove)
                s.props = rmfield(s.props,toRemove);
            end
            
            % Restore the remaining metadata properties.
            t = t.setProperties(s.props);
        end
    end
    %%%%%%%%%%%%%%%%%%%%%%%% END PERSISTENCE BLOCK %%%%%%%%%%%%%%%%%%%%%%%%
end % classdef