Wolfram mathematica 使用mathematica导入大文件/数组
我在Windows7 32位平台上使用mathematica 8.0.1.0。我尝试使用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
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倍。你是对的,内存确实有一个巨大的峰值