我正在使用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向阿伦·霍内克的顶帽。)
在我的机器上(英特尔Core2双CPU 3.17 GHz,4 GB内存,32位Windows 7),这三种方法都使用了大约1.25GB的内存,其中#2和#3的光顺效果略好一些。
如果我不介意丢失精度,那么在创建N[ ]
和myZero
的内部时,它们在内存中的大小最初会增加150 MB,但是将零化所需的内存量(通过上面的方法#1-#3 )从1.25 GB减少到300 MB!这是我的工作解决方案,但很高兴知道处理这个问题的最佳方法。
发布于 2012-01-07 19:14:33
不幸的是我现在没时间了所以我必须简明扼要..。
在处理大数据时,您需要知道Mathematica有一种不同的存储格式,称为打包数组,它比普通数组紧凑得多,而且速度更快,但只适用于机器重数或整数。
如果这不是自动发生的,请评估?Developer`*Packed*
,看看哪些功能可以直接转换到/从它们。
因此,我的解决方案之所以速度快、内存效率高,原因在于它使用了打包数组。我使用Developer`PackedArrayQ
进行测试,我的数组从未被解压缩,我使用了机器reals (我将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[]
或/@
)。
发布于 2012-01-07 22:19:01
首先,我要指出,这个答案必须被看作是对@Szabolcs的答案的补充,在我的结论中,后者是更好的选择。虽然@Szabolcs的解决方案可能是最快和最好的,但它没有达到最初的规范,因为Map
返回原始列表的(修改)副本,而不是“扫描每个元素,并在内存中的那个位置更改它”。这种行为AFAIK仅由Part
命令提供。我将使用他的想法(将所有内容转换为打包数组),以显示在内存中对原始列表进行更改的代码:
In[5]:=
Do[myData[[All,All,i]]=myData[[All,All,i]]- myZero[[i]],
{i,Last@Dimensions@myData}];//Timing
Out[5]= {4.734,Null}
这在概念上等同于问题中列出的方法3,但运行速度要快得多,因为这是一个部分矢量化的解决方案,只需要一个循环。然而,这至少比@Szabolcs的解决方案慢几个数量级。
从理论上讲,这似乎是一种经典的速度/内存权衡:如果您需要速度并有一些空闲内存,@Szabolcs的解决方案就是要走的路。如果您的内存需求很严格,理论上这个较慢的方法将节省中间内存消耗(在@Szabolcs方法中,在myData
分配Map
结果之后,原始列表是垃圾收集的,因此最终的内存使用情况是相同的,但是在计算期间,myData
大小的额外数组由Map
维护)。
然而,在实践中,内存消耗似乎并不小,因为由于某种原因,在计算期间(或之后),由于某种原因在Out
变量中保留了一个额外的列表副本,即使在输出被抑制时也是如此(这也可能是这种影响并非在所有情况下都表现出来)。我还不太明白这一点,但我目前的结论是@Szabolcs的方法在中间内存消耗方面与目前基于现有列表修改的方法一样好。因此,他的方法似乎在所有情况下都是可行的,但我仍然决定发表这个答案作为补充。
https://stackoverflow.com/questions/8772191
复制相似问题