我有几个100x15矩阵;其中一个是距离。当该矩阵的元素超过一个边界时,我想将这些元素重置为零,并将其他三个矩阵的相应元素重置为零。这是我的愚蠢方式(但它有效):
Do[ If[ xnow[[i, j]] > L, xnow[[i, j]] = 0.;
cellactvA[[i, j ]] = 0.;
cellactvB[[i, j ]] = 0.;
cellactvC[[i, j ]] = 0.; ], (* endIF *)
{ i, 1, nstrips}, {j, 1, ncells} ]; (* endDO *)
我尝试了ReplacePart
:
xnow = ReplacePart[ xnow, Position[ xnow, x_?(# > L &) ] ]
(类似这样的东西,我没有得心应用;它已经足够正确地执行了),但是它和循环一样慢并且没有在矩阵xnow中产生正确的替换结构。请告知如何以相当快的方式执行此操作,因为此计算是在执行多次的另一个循环(随着时间的推移)内。当然,整体计算现在非常缓慢。提前谢谢。
以下是我在R中的表现;非常简单快捷:
# -- find indices of cells outside window
indxoutRW <- which( xnow > L, arr.ind=T )
# -- reset cells outside window
cellrateA[indxoutRW] <- 0
cellrateB[indxoutRW] <- 0
cellrateC[indxoutRW] <- 0
# -- move reset cells back to left side
xnow[indxoutRW] <- xnow[indxoutRW] - L
答案 0 :(得分:11)
这个怎么样:
Timing[
matrixMask2 = UnitStep[limit - $xnow];
xnow = $xnow*matrixMask2;
cellactvA2 = $a*matrixMask2;
cellactvB2 = $b*matrixMask2;
cellactvC2 = $c*matrixMask2;
]
如果你想编写快速代码一件事,以确保检查On [“Packing”]没有给出消息;或者至少你理解它们并且知道它们不是问题。
编辑OP评论:
mask = UnitStep[limit - xnow];
{xnow*mask, cellactvA2*mask, cellactvB2*mask, cellactvC2*mask}
希望这有帮助,你仍然需要设置限制。
答案 1 :(得分:8)
以下将基于SparseArrays,避免无关紧要的东西,速度非常快:
extractPositionFromSparseArray[
HoldPattern[SparseArray[u___]]] := {u}[[4, 2, 2]];
positionExtr[x_List, n_] :=
extractPositionFromSparseArray[
SparseArray[Unitize[x - n], Automatic, 1]]
replaceWithZero[mat_, flatZeroPositions_List, type : (Integer | Real) : Real] :=
Module[{copy = Flatten@mat},
copy[[flatZeroPositions]] = If[type === Integer, 0, 0.];
Partition[copy, Last[Dimensions[mat]]]];
getFlatZeroDistancePositions[distanceMat_, lim_] :=
With[{flat = Flatten[distanceMat]},
With[{originalZPos = Flatten@ positionExtr[flat , 0]},
If[originalZPos === {}, #, Complement[#, originalZPos ]] &@
Flatten@positionExtr[Clip[flat , {0, lim}, {0, 0}], 0]]];
现在,我们生成矩阵,确保它们已被打包:
{xnow, cellactvA, cellactvB, cellactvC} =
Developer`ToPackedArray /@ RandomReal[10, {4, 100, 15}];
这是1000次这样做的基准:
In[78]:=
Do[
With[{L = 5},
With[{flatzpos = getFlatZeroDistancePositions[xnow,L]},
Map[replaceWithZero[#,flatzpos ]&,{xnow,cellactvA,cellactvB,cellactvC}]]
],
{1000}]//Timing
Out[78]= {0.203,Null}
请注意,此过程中没有解压缩,但您必须确保从一开始就打包矩阵,并为replaceWithZero
函数选择正确的类型(整数或实数)。 / p>
答案 2 :(得分:3)
另一种似乎很快的方法
xnow = $xnow; a = $a; b = $b; c = $c;
umask = Unitize@Map[If[# > limit, 0, #] &, xnow, {2}];
xnow = xnow*umask; a = a*umask; b = b*umask; c = c*umask;
基于纳赛尔设置中的有限测试,它似乎与基于SparseArray
的面具一样快。
编辑:可与SparseArray
结合使用以获得轻微的加速
umask2=SparseArray[Unitize@Map[If[# > limit, 0, #] &, xnow, {2}]];
xnow = xnow*umask2; a = a*umask2; b = b*umask2; c = c*umask2;
编辑2:灵感来自ruebenko的解决方案,另一个内置函数(不如UnitStep
快,但比其他函数快得多):
umask3 = Clip[xnow, {limit, limit}, {1, 0}];
xnow = xnow*umask3; a = a*umask3; b = b*umask3; c = c*umask3;
答案 3 :(得分:2)
可能是
(*data*)
nRow = 5; nCol = 5;
With[{$nRow = nRow, $nCol = nCol},
xnow = Table[RandomReal[{1, 3}], {$nRow}, {$nCol}];
cellactvA = cellactvB = cellactvC = Table[Random[], {$nRow}, {$nCol}]
];
limit = 2.0;
现在进行更换
pos = Position[xnow, x_ /; x > limit];
{cellactvA, cellactvB, cellactvC} =
Map[ReplacePart[#, pos -> 0.] &, {cellactvA, cellactvB, cellactvC}];
修改(1)强>
这是一个快速的速度比较上面的4种方法,LOOP,然后是Brett,me和Verbeia。也许有人可以仔细检查一下。我为所有人使用了相同的数据。创建一次随机数据,然后将其用于每个测试。相同的限制(称为L)我使用的矩阵大小为2,000乘2,000。
所以下面的速度计时数字不包括数据分配。
我运行一次测试。
这就是我所看到的:
ReplacPart
):21秒SparseArray
):7.27秒MapThread
):32秒ReplacPart
):48秒SparseArray
):16秒MapThread
):79秒所以,似乎SparseArray
是最快的。 (但请检查以确保我没有破坏某些东西)
以下代码:
数据生成
(*data*)
nRow = 2000;
nCol = 2000;
With[{$nRow = nRow, $nCol = nCol},
$xnow = Table[RandomReal[{1, 3}], {$nRow}, {$nCol}];
$a = $b = $c = Table[Random[], {$nRow}, {$nCol}]
];
limit = 2.0;
ReplacePart测试
xnow = $xnow;
a = $a;
b = $b;
c = $c;
Timing[
pos = Position[xnow, x_ /; x > limit];
{xnow, a, b, c} = Map[ReplacePart[#, pos -> 0.] &, {xnow, a, b, c}]][[1]]
SparseArray测试
xnow = $xnow;
a = $a;
b = $b;
c = $c;
Timing[
matrixMask =
SparseArray[Thread[Position[xnow, _?(# > limit &)] -> 0.],
Dimensions[xnow], 1.]; xnow = xnow*matrixMask;
a = a*matrixMask;
b = b*matrixMask;
c = c*matrixMask
][[1]]
MapThread测试
xnow = $xnow;
a = $a;
b = $b;
c = $c;
Timing[
{xnow, a, b, c} =
MapThread[Function[{x, y}, If[x > limit, 0, y]], {xnow, #},
2] & /@ {xnow, a, b, c}
][[1]]
循环测试
xnow = $xnow;
a = $a;
b = $b;
c = $c;
Timing[
Do[If[xnow[[i, j]] > limit,
xnow[[i, j]] = 0.;
a[[i, j]] = 0.;
b[[i, j]] = 0.;
c[[i, j]] = 0.
],
{i, 1, nRow}, {j, 1, nCol}
]
][[1]]
修改(2)强>
所有这一切都让我感到非常困扰。我不明白为什么专门的命令可以更快地循环?
我在Matlab中编写了一个简单的循环测试,就像Bill使用R一样,而且我的时序也低得多。我希望专家可以提出一个更快的方法,因为现在我对此并不满意。
对于3,000乘3,000的矩阵,我正在
Elapsed time is 0.607026 seconds.
这比SparseArray方法快20多倍,它只是一个循环!
%test, on same machine, 4GB ram, timing uses cpu timing using tic/toc
%allocate data
nRow = 3000;
nCol = 3000;
%generate a random matrix of real values
%between 1 and 3
xnow = 1 + (3-1).*rand(nRow,nRow);
%allocate the other 3 matrices
a=zeros(nRow,nCol);
b=a;
c=b;
%set limit
limit=2;
%engine
tstart=tic;
for i=1:nRow
for j=1:nCol
if xnow(i,j) > limit
xnow(i,j) = 0;
a(i,j) = 0;
b(i,j) = 0;
c(i,j) = 0;
end
end
end
toc(tstart)
fyi:使用cputime()给出类似的值.as tic / toc。
答案 4 :(得分:2)
ReplacePart
出了名的慢。
MapThread
应该做你想做的事 - 注意第三个论点。
{xnow, cellactvA, cellactvB, cellactvC} =
RandomReal[{0, 1}, {4, 10, 5}]
L = 0.6;
MapThread[If[#1 > L, 0, #2] &, {xnow, xnow}, 2]
对于所有四个矩阵
{xnow, cellactvA, cellactvB, cellactvC} =
MapThread[Function[{x, y}, If[x > L, 0, y]], {xnow, #},
2] & /@ {xnow, cellactvA, cellactvB, cellactvC}
答案 5 :(得分:2)
这种方法对你有用吗?
matrixMask =
SparseArray[Thread[Position[xnow, _?(# > 0.75 &)] -> 0.],
Dimensions[xnow], 1.];
xnow = xnow * matrixMask;
cellactvA = cellactvA * matrixMask;
cellactvB = cellactvB * matrixMask;
cellactvC = cellactvC * matrixMask;
基本思想是创建一个矩阵,在超过阈值时为零,在其他任何地方创建一个矩阵。然后我们使用逐元素乘法将各种矩阵中的相应元素归零。