网格化分散的数据而无需插值

时间:2018-09-06 14:33:53

标签: matlab matrix multidimensional-array indexing vectorization

我有三个向量XYZ,它们代表在矩阵V(即V = f(X,Y,Z))中找到的某些数据的3d坐标。以下是此数据的一些功能(假设/断言,如果需要的话):

  • XY的长度相同,(通常)与Z的长度不同。

    numel(X) == numel(Y);
    
  • X中唯一元素的数量通常与Y中唯一元素的数量不同。

  • Z中的所有值都是唯一的。

    numel(unique(Z)) == numel(Z);
    
  • V的大小为[numel(X), numel(Z)]

过去,我没有区分XY,而是使用单个索引来引用它们,这使得绘制具有“ XY组合数字”的图表(例如1:numel(X))在一个轴上,Z在另一个轴上,因此V的大小很合适。

目前,我想分别查看XY的效果,这就是为什么我想使用scatter3和{{3的混合物}}。

散点很容易,因为我可以repmat XY沿其单例维度numel(Z)次,Z(使用numel(X))。结果是:

contourslice

对于轮廓,这些要求将数据提供为3d阵列-这意味着我必须将这些点放置在结构化网格中。使用XX创建网格坐标YYZZmeshgrid很简单:

[ XX, YY, ZZ ] = meshgrid( unique(X), unique(Y), unique(Z) );

我正在努力创建3d数组VV

从上图可以看出,大部分体积都不包含点-我非常想保持这种状态。换句话说,理想的VV应该只包含与原始数据集相对应的点,其余的空间应该包含NaN s。

诸如Result of the scattergriddata之类的函数执行插值,这将“填充”点云内部-这是极其不希望的。我认为这里可以使用索引来填充VV中的值来填充V,但我想不出一种方法。

我的问题是:如何生成不包含任何内插数据的VV

这是一个最小的例子:

%% Generate some data:
X = randi(10,100,1);
Y = randi(15,100,1) - 5;
Z = 1:50;
V = X./Y.*Z;

%% Scatter plot:
nXY = numel(X); nZ = numel(Z);
figure();
scatter3( reshape( repmat(X,[1, nZ]),  [], 1), ...
          reshape( repmat(Y,[1, nZ]),  [], 1), ...
          reshape( repmat(Z,[nXY, 1]), [], 1), ...
          [], V(:), '.');

%% Contours:
% Create the 3d grid:
[XX, YY, ZZ] = meshgrid( unique(X), unique(Y), unique(Z) );

% Preallocate VV:
VV = NaN(size(XX));

% Populate VV: <--------------------------------------------- Help needed with this stage
ind = randperm( numel(XX), numel(V) ); % PLACEHOLDER 
VV(ind) = V;

% Plot:
hold on; contourslice(XX, YY, ZZ, VV, X(2), Y(3), Z(10) );

1 个答案:

答案 0 :(得分:2)

我相信,通过将所有网格索引与所有线性数据点进行匹配,可能会导致过度杀伤。为此,我们需要注入一些维度,以便逐元素比较3d数组XX与2d数组X等:

Xbc = reshape(X, [1,1,1,size(X)]);
Ybc = reshape(Y, [1,1,1,size(Y)]);
Zbc = reshape(Z, [1,1,1,size(Z)]);

这些数组的形状经过了调整,以使其与大小为XX的数组[N,M,K]等一起广播(“ bc”代表广播)。因此,逐元素比较现在可以工作了:

match = reshape((XX == Xbc) & (YY == Ybc) & (ZZ == Zbc), [size(XX), numel(V)]);

如果[N,M,K,P,Q]的大小为V,则此逻辑数组的大小为[P,Q]。它包含所需的true个数量完全相同:

>> sum(match(:)) == numel(V)

ans =

  logical

   1

因此,现在我们需要沿前三个维度选择相应的索引,并将它们与V的正确元素配对。我们需要一些线性至多指数肘部润滑脂:

[ii,jj,kk,ll] = ind2sub(size(match), find(match));

现在,左侧的所有数组的大小均为[numel(V), 1];前三个为您提供XX等的索引,最后一个为您提供V的索引。

V_inds = ll;
VV_inds = sub2ind(size(VV), ii, jj, kk);

VV(VV_inds) = V(V_inds);

现在,由于某种原因,我在结果中只看到3750个唯一索引:

>> numel(VV_inds)           

ans =

        5000

>> numel(unique(VV_inds))

ans =

        3750

除了XY的值重复,您的某些原始数据点重叠外,我似乎找不到其他原因。因此,您实际上无法用唯一点的3d网格表示它们(因为某些3d点包含多个数据点)。我相信以下证明了这一点:

>> size(unique([X,Y], 'rows'))

ans =

    75     2

>> size([X,Y])

ans =

   100     2

有100对(x,y)对,但只有75对唯一。无论如何将它们与正交z点集组合在一起,都将在点中重复。因此,您要么必须删除原始数据中的冗余,要么需要找到其他表示形式(或取均值来表示冲突的值)。


我想我也有一个更有效的版本,使用unique在运行期间生成的索引。请注意,我假设您使用的是meshgrid而不是ndgrid来生成网格,以便结果数组的尺寸(以及VV)对应于唯一的大小分别沿XYZ

% take the indices
[uX, ~, iX] = unique(X);
[uY, ~, iY] = unique(Y);
[uZ, ~, iZ] = unique(Z);

% generate mesh and allocate result
[XX, YY, ZZ] = ndgrid(uX, uY, uZ);
VV = NaN(size(XX));

% switch from `iX`, `iY` and `iZ` to a 2d mesh of size `[P,Q]` where `iX` and `iY` are of size `[P,1]` and `iZ` is of size `[Q,1`]:
% a.k.a. lazy repmat
iXbig = iX + 0*iZ.';
iYbig = iY + 0*iZ.';
iZbig = iZ.' + 0*iX;

% turn 3d indices into linear index into VV
VV_inds = sub2ind(size(VV), iXbig, iYbig, iZbig);

% profit
VV(VV_inds) = V;