将列数据转换为ndarray的Matlab方法

4

有没有一种简单的(最好不使用多个for循环)方法来在Matlab中根据一组类别对值向量进行分组?

我有一个数据矩阵,格式如下

CATEG_A    CATEG_B   CATEG_C  ...   VALUE

   1          1        1      ...   0.64
   1          2        1      ...   0.86
   1          1        1      ...   0.74
   1          1        2      ...   0.56
  ...

我需要的是一个N维数组

等等,什么是N维数组呢?

 all_VALUE( CATEG_A, CATEG_B, CATEG_C, ..., index ) = VALUE_i

当然,可能会有许多具有相同类别组合的值,因此size(end)将是最大类别中的值数量 - 剩余项目将用nan填充。
另外,我也可以接受以下方式:
 all_VALUE { CATEG_A, CATEG_B, CATEG_C, ... } ( index )

即一个向量的单元格数组。我想这有点像创建一个n维透视表,而不是计算平均值。

我在帮助文档中找到了这个函数。

A = accumarray(subs,val,[],@(x) {x})

但是我无法理解如何使它做我想要的事情!

2个回答

2

这个也很混乱,但是有效。它采用了ND数组的方式。

X = [1        1        1        0.64
     1        2        1        0.86
     1        1        1        0.74
     1        1        2        0.56]; %// data
N = size(X,1); %// number of values
[~, ~, label] = unique(X(:,1:end-1),'rows'); %// unique labels for indices
cumLabel = cumsum(sparse(1:N, label, 1),1); %// used for generating a cumulative count
    %// for each label. The trick here is to separate each label in a different column
lastInd = full(cumLabel((1:N).'+(label-1)*N)); %'// pick appropriate values from 
    %// cumLabel to generate the cumulative count, which will be used as last index
    %// for the result array
sizeY = [max(X(:,1:end-1),[],1) max(lastInd)]; %// size of result
Y = NaN(sizeY); %// initiallize result with NaNs
ind = mat2cell([X(:,1:end-1) lastInd], ones(1,N)); %// needed for comma-separated list
Y(sub2ind(sizeY, ind{:})) = X(:,end); %// linear indexing of values into Y

您的示例结果是以下4D数组:
>> Y
Y(:,:,1,1) =
    0.6400    0.8600
Y(:,:,2,1) =
    0.5600       NaN
Y(:,:,1,2) =
    0.7400       NaN
Y(:,:,2,2) =
   NaN   NaN

不错,我一开始也尝试过,但是在每个标签部分的累计计数方面卡住了。@SanjayManohar 这可能是更好的解决方案... - Dan
@Dan 谢谢。你的解决方案在内存方面实际上更有效,因为它提供了单元数组而不是 N-D 数组。 - Luis Mendo
1
太好了。谢谢你还向我介绍了unique函数的第三个输出。而且 ind 变量告诉每个元素“该去哪里”,这真是太美妙了。 - Sanjay Manohar

2

虽然有点混乱,但这里有一个解决方案

[U,~,subs] = unique(X(:,1:end-1),'rows');

sz = max(U);
Uc = mat2cell(U, size(U,1), ones(1,size(U,2)));
%// Uc is converted to cell matrices so that we can take advantage of the {:} notation which returns a comma-separated-list which allows us to pass a dynamic number of arguments to functions like sub2ind

I = sub2ind(sz, Uc{:});

G = accumarray(subs, X(:,end),[],@(x){x});

A{prod(max(U))} = [];  %// Pre-assign the correct number of cells to A so we can reshape later
A(I) = G;
reshape(A, sz)

在您提供的示例数据中(忽略 ...),这将返回:
A(:,:,1) = 

    [2x1 double]    [0.8600]


A(:,:,2) = 

    [0.5600]    []

其中A(1,1,1)[0.74; 0.64]


1
哇 - 哇!!那太棒了。完美运行。我会花些时间研究你的代码。 Accumarray 很强大。 - Sanjay Manohar
你真的需要将 sz 定义为一个单元数组吗?因为你只是使用 [sz {:}] - Luis Mendo
@SanjayManohar accumarray 绝对是非常强大的。它在 StackOverflow-[tag:matlab] 上有很多粉丝 :-) - Luis Mendo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接