2014-12-24 88 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的問題。