Pushes NaNs to the bottom of each column of X.

pushnans( X,truncate )
function X = pushnans( X,truncate )
% X = PUSHNANS(X,truncate)
% Pushes nans to the bottom of each column of X.
% The second input is an optional flag.  If true, the whole-nan rows at the
% bottom of X are removed.
% DM, Apr 2013

    NAN_THRESHOLD_FRACTION = 0.9; %I haven't actually optimised this value, proably system and version dependant
    if sum(sum(isnan(X)))/numel(X) > NAN_THRESHOLD_FRACTION %Note we could do a random sample of X rather than all of it, but this is already pretty fast
        pickOutNonNansMethod %when there are few non-nans, do this
        sortAllMethod %when there are loads of non-nans do this

    function sortAllMethod
        [s1,s2] = size(X);
        %get a matrix of row indices with indices refering to non-nans at the top of the columns in the original order
        [~,row] = sort(isnan(X)); 
        %use the row indicies and manually calcualte the full-index to rearange X
        X = X(bsxfun(@plus,uint32((0:s2-1)*s1),uint32(row)));

        if exist('truncate','var') && truncate
            s2 = max(sum(~isnan(X)));
            X(s2+1:end,:) = [];

    function pickOutNonNansMethod
        %In this method we use find to get a list of column indices for all the
        %non-nan values. We then use "manually" work out the row indicies
        one = uint32(1);

        %get a list of non-nan vals and their column indices
        goodVal = X(~isnan(X));
        [~, goodIndCol] = find(~isnan(X));
        goodIndCol = uint32(goodIndCol);
        %we'll need these dimensions
        [s1,s2] = size(X);
        s0 = uint32(numel(goodIndCol));
        %work out the row indices for each of the non-nan vals in our list
        isColHead = [single(1) ; goodIndCol(1:end-1)~=goodIndCol(2:end)];
        indColHead = uint32(cumsum(isColHead));
        colHead = uint32(find(isColHead));
        goodRowInd = (one:s0)' - colHead(indColHead) + one;

        %prepare a new whole-nan matrix of the correct size
        if exist('truncate','var') && truncate
            s1 = max(goodRowInd);
        X = nan(s1,s2);
        %use our lovely indices to place the non-nans at the top of the rows
        X((goodIndCol-one)*uint32(s1) + goodRowInd) = goodVal;


Contact us