Wolfram mathematica 使用mathematica导入大文件/数组

Wolfram mathematica 使用mathematica导入大文件/数组,wolfram-mathematica,Wolfram Mathematica,我在Windows7 32位平台上使用mathematica 8.0.1.0。我尝试使用 Import[file,”Table”] 只要文件(文件中的数组)足够小,它就可以正常工作。但对于更大的文件(38MB)/数组(9429乘以2052),我得到的信息是: No more memory available. Mathematica kernel has shut down. Try quitting other applications and then retry. 在拥有更多主内存的W

我在Windows7 32位平台上使用mathematica 8.0.1.0。我尝试使用

Import[file,”Table”]
只要文件(文件中的数组)足够小,它就可以正常工作。但对于更大的文件(38MB)/数组(9429乘以2052),我得到的信息是:

No more memory available. Mathematica kernel has shut down. Try quitting other applications and then retry.
在拥有更多主内存的Windows7 64位平台上,我可以导入更大的文件,但我认为有一天,当文件增长/阵列有更多行时,我也会遇到同样的问题

因此,我试图找到一个导入大文件的解决方案。搜索了一段时间后,我在这里看到了一个类似的问题:。 但是,我的mathematica知识似乎不足以使建议的OpenRead、ReadList或类似内容适应我的数据(参见示例文件)。 问题是,我需要文件中数组的其余程序信息,例如维度、某些列和行中的Max/Min,并且我正在对某些列和每一行执行操作。 但是,当我使用例如ReadList时,我从未获得与导入相同的数组信息(可能是因为我使用了错误的方法)


这里有人能给我一些建议吗?我将感谢大家的支持

由于某些原因,当前针对类型
(表格数据)的
导入
实现的内存效率非常低。下面,我尝试在某种程度上纠正这种情况,同时仍然重用Mathematica的高级导入功能(通过
ImportString
)。对于稀疏表,提出了一个单独的解决方案,这可以大大节省内存

通用内存高效解决方案 下面是一个更节省内存的函数:

Clear[readTable];
readTable[file_String?FileExistsQ, chunkSize_: 100] :=
   Module[{str, stream, dataChunk, result , linkedList, add},
      SetAttributes[linkedList, HoldAllComplete];
      add[ll_, value_] := linkedList[ll, value];           
      stream  = StringToStream[Import[file, "String"]];
      Internal`WithLocalSettings[
         Null,
         (* main code *)
         result = linkedList[];
         While[dataChunk =!= {},
           dataChunk = 
              ImportString[
                 StringJoin[Riffle[ReadList[stream, "String", chunkSize], "\n"]], 
                 "Table"];
           result = add[result, dataChunk];
         ];
         result = Flatten[result, Infinity, linkedList],
         (* clean-up *)
         Close[stream]
      ];
      Join @@ result]
In[11]:= 
(tsparse= readSparseTable["C:\\Users\\Archie\\Downloads\\ExampleFile\\ExampleFile.txt"]);//Timing
Out[11]= {39.874,Null}
In[18]:= 
(t = readTable["C:\\Users\\Archie\\Downloads\\ExampleFile\\ExampleFile.txt"]);//Timing
Out[18]= {38.516,Null}
在这里,我使用标准的
导入
,为您的文件:

In[3]:= used = MaxMemoryUsed[]
Out[3]= 18009752

In[4]:= 
tt = readTable["C:\\Users\\Archie\\Downloads\\ExampleFile\\ExampleFile.txt"];//Timing
Out[4]= {34.367,Null}

In[5]:= used = MaxMemoryUsed[]-used
Out[5]= 228975672

In[6]:= 
t = Import["C:\\Users\\Archie\\Downloads\\ExampleFile\\ExampleFile.txt","Table"];//Timing
Out[6]= {25.615,Null}

In[7]:= used = MaxMemoryUsed[]-used
Out[7]= 2187743192

In[8]:= tt===t
Out[8]= True
您可以看到,我的代码的内存效率大约是
Import
的10倍,但不会慢很多。您可以通过调整
chunkSize
参数来控制内存消耗。生成的表占用大约150-200 MB的RAM

编辑

稀疏表的效率更高 我想说明如何使用
SparseArray
-s使该函数在导入期间的内存效率提高2-3倍,再加上表占用的最终内存效率提高一个数量级。我们获得内存效率提高的程度在很大程度上取决于表的稀疏程度。在您的示例中,表非常稀疏

稀疏阵列的剖析 我们从一个普遍有用的API开始,该API用于构建和解构
SparseArray
对象:

ClearAll[spart, getIC, getJR, getSparseData, getDefaultElement, makeSparseArray];
HoldPattern[spart[SparseArray[s___], p_]] := {s}[[p]];
getIC[s_SparseArray] := spart[s, 4][[2, 1]];
getJR[s_SparseArray] := Flatten@spart[s, 4][[2, 2]];
getSparseData[s_SparseArray] := spart[s, 4][[3]];
getDefaultElement[s_SparseArray] := spart[s, 3];
makeSparseArray[dims : {_, _}, jc : {__Integer}, ir : {__Integer}, 
     data_List, defElem_: 0] :=
 SparseArray @@ {Automatic, dims, defElem, {1, {jc, List /@ ir}, data}};
下面是一些简短的评论。下面是一个稀疏数组示例:

In[15]:= 
ToHeldExpression@ToString@FullForm[sp  = SparseArray[{{0,0,1,0,2},{3,0,0,0,4},{0,5,0,6,7}}]]

Out[15]= 
Hold[SparseArray[Automatic,{3,5},0,{1,{{0,2,4,7},{{3},{5},{1},{5},{2},{4},{5}}},
{1,2,3,4,5,6,7}}]]
(为了便于阅读,我使用
ToString
-
ToHeldExpression
循环将
表单中的
列表[…]
等转换回
{…}
)。这里,
{3,5}
显然是维度。接下来是默认元素
0
。接下来是一个嵌套列表,我们可以将其表示为
{1,{ic,jr},spara}
。这里,
ic
在我们添加行时给出了非零元素的总数-因此它是第一个0,然后是第一行后的2,第二个再添加2,最后一个再添加3。下一个列表,
jr
给出了所有行中非零元素的位置,因此第一行为
3
5
,第二行为
1
5
,最后一行为
2
4
5
。关于哪一行在这里开始和结束,没有任何混淆,因为这可以由
ic
列表确定。最后,我们有
SPARA
,这是一个从左到右逐行读取的非零元素列表(顺序与
jr
列表相同)。这解释了
SparseArray
-s存储元素的内部格式,并希望澄清上述函数的作用

代码 基准和比较 以下是已使用内存(新内核)的起始数量:

我们称我们的功能为:

Clear[readTable];
readTable[file_String?FileExistsQ, chunkSize_: 100] :=
   Module[{str, stream, dataChunk, result , linkedList, add},
      SetAttributes[linkedList, HoldAllComplete];
      add[ll_, value_] := linkedList[ll, value];           
      stream  = StringToStream[Import[file, "String"]];
      Internal`WithLocalSettings[
         Null,
         (* main code *)
         result = linkedList[];
         While[dataChunk =!= {},
           dataChunk = 
              ImportString[
                 StringJoin[Riffle[ReadList[stream, "String", chunkSize], "\n"]], 
                 "Table"];
           result = add[result, dataChunk];
         ];
         result = Flatten[result, Infinity, linkedList],
         (* clean-up *)
         Close[stream]
      ];
      Join @@ result]
In[11]:= 
(tsparse= readSparseTable["C:\\Users\\Archie\\Downloads\\ExampleFile\\ExampleFile.txt"]);//Timing
Out[11]= {39.874,Null}
In[18]:= 
(t = readTable["C:\\Users\\Archie\\Downloads\\ExampleFile\\ExampleFile.txt"]);//Timing
Out[18]= {38.516,Null}
因此,它的速度与
readTable
相同。内存使用情况如何

In[12]:= used = MaxMemoryUsed[]-used
Out[12]= 80863296
我认为,这是相当了不起的:我们使用的内存是磁盘上文件占用内存的两倍。但是,更值得注意的是,最终内存使用量(在计算完成后)已显著减少:

In[13]:= MemoryInUse[]
Out[13]= 26924456
这是因为我们使用了
SparseArray

In[15]:= {tsparse,ByteCount[tsparse]}
Out[15]= {SparseArray[<326766>,{9429,2052}],12103816}
将稀疏表转换回正常值后,结果相同:

In[20]:= Normal@tsparse==t
Out[20]= True
虽然普通表占用的空间大得多(似乎
字节计数
会将占用的内存过多计算3-4倍,但实际差异仍然至少是数量级):


你真的是说当你读取一个只有38MB的文件时会出现这个错误吗?@Nasser这是一种特殊的表格数据压缩格式,有点像二进制格式。毫不奇怪,当解包到Mathematica的符号数据结构(列表)中时,它需要更多的内存。然而,这也不能解释如此巨大的内存需求——请看下面我的答案。我导入这个测试文件没有任何问题。一次读入的数据字节数为619900248,因此大约为620MB。这可能会导致您的问题。@Sjoerd我确实遇到了问题-在某些情况下,它请求了超过2GB的RAM,您可以通过使用系统监视器看到这一点。因为我在一个64位系统上,内存为6Gb,所以这并不是致命的。但我相信,对于运行其他东西的32位系统来说,这可能是一个杀手。依我看,这是当前
Import
实现中的一个明显缺陷-请参阅我的答案以获取替代方案。至于
ByteCount
,这也是一种欺骗,因为最终的表实际上占用的内存比
ByteCount
@Leonid所指示的内存少3倍。你是对的,内存确实有一个巨大的峰值