首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >转换嵌套列表而不复制或丢失精度

转换嵌套列表而不复制或丢失精度
EN

Stack Overflow用户
提问于 2012-01-07 18:57:25
回答 2查看 253关注 0票数 6

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

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

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

下面的独立代码捕获了我想要做的事情的所有方面:

代码语言:javascript
运行
复制
(* 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!这是我的工作解决方案,但很高兴知道处理这个问题的最佳方法。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-01-07 19:14:33

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

在处理大数据时,您需要知道Mathematica有一种不同的存储格式,称为打包数组,它比普通数组紧凑得多,而且速度更快,但只适用于机器重数或整数。

如果这不是自动发生的,请评估?Developer`*Packed*,看看哪些功能可以直接转换到/从它们。

因此,我的解决方案之所以速度快、内存效率高,原因在于它使用了打包数组。我使用Developer`PackedArrayQ进行测试,我的数组从未被解压缩,我使用了机器reals (我将N[]应用于一切)。

代码语言:javascript
运行
复制
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[]/@)。

票数 6
EN

Stack Overflow用户

发布于 2012-01-07 22:19:01

首先,我要指出,这个答案必须被看作是对@Szabolcs的答案的补充,在我的结论中,后者是更好的选择。虽然@Szabolcs的解决方案可能是最快和最好的,但它没有达到最初的规范,因为Map返回原始列表的(修改)副本,而不是“扫描每个元素,并在内存中的那个位置更改它”。这种行为AFAIK仅由Part命令提供。我将使用他的想法(将所有内容转换为打包数组),以显示在内存中对原始列表进行更改的代码:

代码语言:javascript
运行
复制
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的方法在中间内存消耗方面与目前基于现有列表修改的方法一样好。因此,他的方法似乎在所有情况下都是可行的,但我仍然决定发表这个答案作为补充。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8772191

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档