我正在使用Mathematica 7处理大型数据集。数据集是有符号整数的三维数组。可以认为这三个级别分别对应于每个镜头X个点,每次扫描Y个镜头和每组Z个扫描。

我也有一个“调零”镜头(包含X点,它们是整数的有符号分数),我想从数据集中的每个镜头中减去这些点。之后,我将不再需要原始数据集。

在此过程中,如何在不创建数据集或其一部分的新副本的情况下执行此转换?从概念上讲,数据集位于内存中,我想扫描每个元素,然后在内存中的该位置进行更改,而不必将其永久复制到其他内存位置。

以下独立代码包含了我正在尝试做的所有方面:

(* Create some offsetted data, and a zero data set. *)
myData = Table[Table[Table[RandomInteger[{1, 100}], {k, 500}], {j, 400}], {i, 200}];
myZero = Table[RandomInteger[{1, 9}]/RandomInteger[{1, 9}] + 50, {i, 500}];

(* Method 1 *)
myData = Table[
   f1 = myData[[i]];
   Table[
     f2 = f1[[j]];
     f2 - myZero, {j, 400}], {i, 200}];

(* Method 2 *)
Do[
 Do[
  myData[[i]][[j]] = myData[[i]][[j]] - myZero, {j, 400}], {i, 200}]

(* Method 3 *)
Attributes[Zeroing] = {HoldFirst};
Zeroing[x_] := Module[{},
   Do[
     Do[
       x[[i]][[j]] = x[[i]][[j]] - myZero, {j, Length[x[[1]]]}
       ], {i, Length[x]}
     ]
 ];

(注意:方法3的Aaron Honecker提示。)

在我的机器(Intel Core2 Duo CPU 3.17 GHz,4 GB RAM,32位Windows 7)上,这三种方法都使用大约1.25 GB的内存,而#2和#3的整流罩稍好一些。

如果我不介意失去精度,则在创建N[ ]myData的内部时将myZero包裹起来,最初会增加150 MB的内存大小,但会减少调零所需的内存量(通过方法#1-#3以上)从1.25 GB降至仅300 MB!那是我的工作解决方案,但是很高兴知道解决此问题的最佳方法。

最佳答案

不幸的是我现在没有时间了,所以我必须简明扼要...

当处理大数据时,您需要意识到Mathematica具有另一种称为打包数组的存储格式,该格式比常规范式更紧凑且速度更快,但仅适用于机器实数或整数。

请评估?Developer`*Packed*,以了解哪些功能可用于直接与它们进行相互转换,如果这不是自动发生的。

因此,为什么我的解决方案快速且内存高效的原因的简要解释是它使用压缩数组。我使用Developer`PackedArrayQ测试了我的数组永远不会解压,并且使用了机器实数(我将N[]应用于所有内容)

In[1]:= myData = N@RandomInteger[{1, 100}, {200, 400, 500}];

In[2]:= myZero =
  Developer`ToPackedArray@
   N@Table[RandomInteger[{1, 9}]/RandomInteger[{1, 9}] + 50, {i, 500}];

In[3]:= myData = Map[# - myZero &, myData, {2}]; // Timing

Out[3]= {1.516, Null}

另外,您要求的操作(“我想扫描每个元素,并在内存中的该位置更改它”)被称为映射(请参阅Map[]/@)。

10-08 09:20
查看更多