在Matlab中基于单元格的现有列创建新变量

时间:2014-07-19 14:46:22

标签: matlab pivot-table cell-array

我有一个600 000行和5列的单元格数组。在以下示例中,我仅提供3个不同的代码和5年的时间段。输入:

c1   c2        c3        c4  c5 

1   2006    20060425    559 'IA'
1   2007    20070129    559 'LO'
1   2007    20070826    559 'VC'
1   2008    20080825     34 'VP'
1   2009    20090116     34 'ZO'
4   2007    20070725     42 'OI'
4   2008    20080712     42 'TF'
4   2008    20080428     42 'XU'
11  2007    20070730    118 'AM'
11  2008    20080912    118 'HK'
11  2009    20090318      2 'VT'
11  2010    20100121      2 'ZZ'

我想获得一个新变量,它为每个代码(c1)提供样本中c1出现的年份和相应的c4值。例如:

输出:

x  2006 2007 2008 2009 2010
1  559  559  34   34   - 
4   -   42   42   -    -
11  -   118  118  2    2 

要访问我的单元格数组,这是我到目前为止使用的代码:

a1=T_ANNDAT3;
a2=I{:,7};
a3=I{:,6};
a4=I{:,16};
a5=I{:,1};
TRACK_AN = [num2cell([a2 a1 a4 a3]) a5];
TRACK_AN(cell2mat(TRACK_AN(:,1))==0,:)=[];
[~,indTA,~] = unique(strcat(TRACK_AN(:,1),TRACK_AN(:,2),TRACK_AN(:,4),TRACK_AN(:,5)));
TRACK_AN = TRACK_AN(indTA,:);

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:3)

您可以使用unique非常轻松地计算出这一点。关键是使用'rows'标记作为unique的第二个参数,这样您就可以找出矩阵的唯一条目。我们只需要矩阵的第一,第二和第四列用于此过程,因此我们可以将这些列子集化。您还需要使用unique的其他输出参数,以便我们可以确定原始单元格数组中唯一行的确切位置。这是算法下一部分所需的关键属性。

在第一次unique来电中找到唯一的小组数组后,我们再应用unique两次 - 一个用于c1列,另一个用于c2列1}}所以我们可以索引ID和年份。我们将使用unique的第三个输出参数,以便我们可以将每列中的每个唯一编号分配给唯一ID。然后,我们使用accumarray创建上面看到的最终矩阵,将第一列中的值作为行进行分箱,第二列作为此最终矩阵的列。换句话说:

%// Create cell array as per your example
C = {1   2006    20060425    559 'IA'
1   2007    20070129    559 'LO'
1   2007    20070826    559 'VC'
1   2008    20080825     34 'VP'
1   2009    20090116     34 'ZO'
4   2007    20070725     42 'OI'
4   2008    20080712     42 'TF'
4   2008    20080428     42 'XU'
11  2007    20070730    118 'AM'
11  2008    20080912    118 'HK'
11  2009    20090318      2 'VT'
11  2010    20100121      2 'ZZ'};

%// Get only those columns that are relevant
%// These are the first, second and fourth columns
Cmat = unique(cell2mat(C(:,[1 2 4])), 'rows');

%// Bin each of the first and second columns
%// Give them a unique ID per unique number    
[~,~,ind] = unique(Cmat(:,1));
[~,~,ind2] = unique(Cmat(:,2));

%// Use accumarray to create your matrix    
%// Edit - Thanks to Amro
%// Any values that are missing replace with NaN
finalMat = accumarray([ind ind2], Cmat(:,3), [], [], NaN);

输出是:

finalMat =

559   559    34    34   NaN
NaN    42    42   NaN   NaN
NaN   118   118     2     2

我用NaN替换了缺少的值来表示缺失值。

希望这有帮助!

答案 1 :(得分:3)

@ rayryeng的解决方案略有不同:

% data as cell array
C = {
    1   2006    20060425    559 'IA'
    1   2007    20070129    559 'LO'
    1   2007    20070826    559 'VC'
    1   2008    20080825     34 'VP'
    1   2009    20090116     34 'ZO'
    4   2007    20070725     42 'OI'
    4   2008    20080712     42 'TF'
    4   2008    20080428     42 'XU'
    11  2007    20070730    118 'AM'
    11  2008    20080912    118 'HK'
    11  2009    20090318      2 'VT'
    11  2010    20100121      2 'ZZ'
};

% we are only interested in three columns
CC = cell2mat(C(:,[1 2 4]));

% unique codes/years and their mapping
[codes,~,codesInd] = unique(CC(:,1));
[years,~,yearsInd] = unique(CC(:,2));

% pivot table
out = accumarray([codesInd yearsInd], CC(:,3), [], @max, NaN)

预期的结果:

>> out
out =
   559   559    34    34   NaN
   NaN    42    42   NaN   NaN
   NaN   118   118     2     2

或漂亮地打印成表格:

>> t = array2table(out, ...
    'RowNames',cellstr(num2str(codes,'code_%d')), ...
    'VariableNames',cellstr(num2str(years,'year_%d')));

>> t
t = 
               year_2006    year_2007    year_2008    year_2009    year_2010
               _________    _________    _________    _________    _________
    code_1     559          559           34           34          NaN      
    code_4     NaN           42           42          NaN          NaN      
    code_11    NaN          118          118            2            2