2014-12-24 57 views
0

我有以下表重塑Matlab的表

name = ['A' 'A' 'A' 'B' 'B' 'C' 'C' 'C' 'C' 'D' 'D' 'E' 'E' 'E']'; 
value = randn(14, 1); 
T = table(name, value); 

I,E。

T = 

name  value 
____ _________ 

A  0.0015678 
A  -0.76226 
A   0.98404 
B   -1.0942 
B   0.71249 
C   1.688 
C   1.4001 
C   -0.9278 
C   -1.3725 
D   0.11563 
D  0.076776 
E   1.0568 
E   1.1972 
E   0.29037 

我想通过以下方式来改造它:取前两个单元格中value对应不同的值name,并把它放在5x2矩阵。该矩阵将具有对应于不同的名称A,B,C,D,E和对应于values列的行,例如前两行是

0.0015678 -0.76226 
-1.0942 0.71249 

回答

3

这可以使用自定义函数与accumarray完成。第一步是将name列的T转换为数字向量;然后可以应用accumarray

此方法要求T根据第1列进行排序,因为只有在这种情况下,accumarray才能保证顺序(如其文档中所示)。因此,如果T可能未被排序(尽管它在您的示例中),请先使用sortrows对其进行排序。

T = sortrows(T, 1); %// you can remove this line if T is guaranteed to be sorted 
[~, ~, names] = unique(T(:,1)); %// names as a numeric vector 
result = cell2mat(accumarray(names, T.value, [], @(x) {x([1 2]).'})); 
+0

'accumarray'非常好的工作!没想过在这里使用它。 – rayryeng

3

首先弄清楚,其中每个名字具有位于表中的值,然后通过每个名称周期,并把为每名成单独的单元阵列中遇到的前两个值。一旦大功告成,重塑矩阵5 x 2正如你所说。因此,做这样的事情:

names = unique(T.name); %// 1 
ind = arrayfun(@(x) find(T.name == x), names, 'uni', 0); %// 2 
vals = cellfun(@(x) T.value(x(1:2)), ind, 'uni', 0); %// 3 
m = [vals{:}].'; %// 4 

让我们慢慢浏览每一行代码。


1号线

第一行通过unique找到所有独特名称,我们将它们存储到names

2号线

下一行遍历所有独特的名字,并认为这些位置/表中的行共享特定的名称。我用arrayfun并通过每名names,找到那些共享相同的名称作为一个我们正在寻找行,并将这些行的位置成单个细胞;这些存储在ind。要找到每一个有效的名字在我们的桌子的位置,我用find和位置放置的列向量。因此,我们将有五个列向量,其中每个列向量被放入一个单独的单元格中。这些列向量会告诉我们哪些行与位于表中的特定名称匹配。

3号线

下一行使用cellfun要经过的每个细胞的ind并提取共享特定名称的前两点的位置,索引到value字段中为表拉那两个值,并且这些值作为两元素向量放置到每个名称的单个单元格中。

行#4

最后一行代码简单地展开每个两元素向量。每个名字的前两个元素,会存储到。为了让它们成行,我只需转置展开。输出矩阵存储到m


如果你想看到的输出看起来像什么,这是我所得到的,当我与你的示例表运行上面的代码:

m = 

    0.0016 -0.7623 
    -1.0942 0.7125 
    1.6880 1.4001 
    0.1156 0.0768 
    1.0568 1.1972 

注意,我只显示前5精确度的数字,所以最后会有一些舍入。但是,这只是为了显示目的,所以我得到的结果等同于您对输出的期望。


希望这有助于!

+0

一如既往的彻底清晰的解释! –

+0

@LuisMendo谢谢你我的朋友!圣诞节快乐! – rayryeng

+0

谢谢!对你也一样! –

2

如果你想使用的表,你可以尝试这样的事:

count = 1; 
U = unique(table2array(T(:,1))); 
for ii = 1:size(U,1) 
    A = find(table2array(T(:,1)) == U(ii)); 
    A = A(1:2); 
    B(count,1:2) = table2array(T(A,2)); 
    count = count + 1; 
end 

就个人而言,我会觉得这个简单的做你的名字和值数组,而忘记了桌子上。如果这是一项要求,那么我明白,但是我仍然会提供我的解决方案。它可以提供一些洞察力的任何方式。

count = 1; 
U = unique(name); 
for ii = 1:size(U,1) 
    A = find(name == U(ii)); 
    A = A(1:2); 
    B(count,1:2) = value(A); 
    count = count + 1; 
end 

快速和肮脏,但希望它是够好的。祝你好运。

+0

第二种方法几乎与我所做的一样,但我决定保留在“表”的约束范围内并使用点符号来引用相应的字段。 +1 btw。 – rayryeng

0

另一种解决方案是更容易管理和容易扩展存在。由于MATLAB R2013b,您可以使用专门的函数来旋转表格(这是您想要做的):unstack

为了得到正是你想要的东西,你需要一个额外的变量添加到您的表会指示复制:

name = ['A' 'A' 'A' 'B' 'B' 'C' 'C' 'C' 'C' 'D' 'D' 'E' 'E' 'E']'; 
value = randn(14, 1); 
rep = [1, 2, 3, 1, 2, 1, 2, 3, 4, 1, 2, 1, 2, 3]; 
T = table(name, value, rep); 

T = 

name  value  rep 
____ _________ ___ 

A   0.53767 1 
A   1.8339 2 
A   -2.2588 3 
B   0.86217 1 
B   0.31877 2 
C   -1.3077 1 
C  -0.43359 2 
C   0.34262 3 
C   3.5784 4 
D   2.7694 1 
D   -1.3499 2 
E   3.0349 1 
E   0.7254 2 
E  -0.063055 3 

然后你只需要使用unstack这样的:

pivotTable = unstack(T, 'value','name') 

pivotTable = 

    rep  A   B   C   D   E  
    ___ _______ _______ ________ _______ _________ 

    1  0.53767 0.86217  -1.3077  2.7694  3.0349 
    2  1.8339 0.31877 -0.43359 -1.3499  0.7254 
    3  -2.2588  NaN  0.34262  NaN -0.063055 
    4   NaN  NaN  3.5784  NaN   NaN 

之后,如果你仍然想要,这是re-arranging the table的问题。