Matrix 朱莉娅:如何修改保存为二进制文件的矩阵列?

Matrix 朱莉娅:如何修改保存为二进制文件的矩阵列?,matrix,binary,save,julia,Matrix,Binary,Save,Julia,我正在处理大型数据矩阵(Nrow x Ncol),这些数据矩阵太大,无法存储在内存中。相反,在我的工作领域,将数据保存到二进制文件是标准的。由于工作的性质,我一次只需要访问矩阵的一列。我还需要能够修改列,然后将更新的列保存回二进制文件。到目前为止,我已经设法找出了如何将矩阵保存为二进制文件,以及如何将矩阵的1列从二进制文件读入内存。但是,在编辑列的内容后,我无法确定如何将该列保存回二进制文件 例如,假设数据文件是已保存到磁盘的32位标识矩阵 Nrow = 500 Ncol = 325 data

我正在处理大型数据矩阵(Nrow x Ncol),这些数据矩阵太大,无法存储在内存中。相反,在我的工作领域,将数据保存到二进制文件是标准的。由于工作的性质,我一次只需要访问矩阵的一列。我还需要能够修改列,然后将更新的列保存回二进制文件。到目前为止,我已经设法找出了如何将矩阵保存为二进制文件,以及如何将矩阵的1列从二进制文件读入内存。但是,在编辑列的内容后,我无法确定如何将该列保存回二进制文件

例如,假设数据文件是已保存到磁盘的32位标识矩阵

Nrow = 500
Ncol = 325
data = eye(Float32,Nrow,Ncol)
stream_data = open("data","w")
write(stream_data,data[:])
close(stream_data)
从磁盘读取整个文件,然后将其重塑为矩阵非常简单:

stream_data = open("data","r")
data_matrix = read(stream_data,Float32,Nrow*Ncol)
data_matrix = reshape(data_matrix,Nrow,Ncol)
close(stream_data)
正如我之前所说,我使用的数据矩阵太大,无法读入内存,因此上面编写的代码通常无法执行。相反,我需要一次处理一列。以下是将矩阵的1列(例如第7列)读入内存的解决方案:

icol = 7
stream_data = open("data","r")
position_data = 4*Nrow*(icol-1)
seek(stream_data,position_data)
data_col = read(stream_data,Float32,Nrow)
close(stream_data)
请注意,“position_data”变量中的系数“4”是因为我使用的是Float32。此外,我不完全理解seek命令在这里的作用,但它似乎根据以下测试为我提供了正确的输出:

data == data_matrix     # true
data[:,7] == data_col   # true
为了解决这个问题,假设我已确定我加载的列(即第7列)需要替换为零:

data_col = zeros(Float32,size(data_col))
现在的问题是如何在不影响任何其他数据的情况下将此列保存回二进制文件。当然,我打算用“写”来完成这项任务。然而,我并不完全确定如何进行。我知道我需要从打开数据流开始;但是,我不确定我需要使用什么“模式”:“w”、“w+”、“a”或“a+”?以下是使用“w”的失败尝试:

原始二进制文件(在我尝试编辑二进制文件失败之前)占用了磁盘上的650000字节。这与矩阵大小为500x325且Float32数字占用4个字节(即4*500*325=650000)的事实一致。然而,在我尝试编辑二进制文件之后,我发现二进制文件现在只占用14000字节的空间。一些快速的心算表明14000字节对应于7列数据(4*500*7=14000)。快速检查确认二进制文件已将所有原始数据替换为大小为500x7的新矩阵,其元素均为零

stream_data = open("data","r")
data_new_matrix = read(stream_data,Float32,Nrow*7)
data_new_matrix = reshape(data_new_matrix,Nrow,7)
sum(abs(data_new_matrix))  # 0.0f0
为了只修改二进制文件中的第7列“列”,我需要做什么/更改什么?

您可以根据您描述的需要使用:

data=SharedArray("/some/absolute/path/to/a/file", Float32,(Nrow,Ncols))
# do something with data
data[:,1]=a[:,1].+1
exit()

# restart julia
data=SharedArray("/some/absolute/path/to/a/file", Float32,(Nrow,Ncols))
@show data[1,1]
# prints 1
现在,请注意,您应该处理从/到该文件的读/写同步(如果您有异步工作进程),并且不应该更改阵列的大小(除非您知道自己在做什么)。

而不是

icol = 7
stream_data = open("data","w")
position_data = 4*Nrow*(icol-1)
seek(stream_data,position_data)
write(stream_data,data_col)
close(stream_data)
在OP中,写下

icol = 7
stream_data = open("data","r+")
position_data = 4*Nrow*(icol-1)
seek(stream_data,position_data)
write(stream_data,data_col)
close(stream_data)
i、 e.用
“r+”
替换
“w”
,一切正常


open
的引用是,它解释了各种模式。最好不要将
open
与原始的有点混乱但肯定较慢的字符串参数一起使用。

这里有什么用处吗?也许可以将向量更新中的
stream\u data=open(“data”,“w”)
更改为
stream\u data=open(“data”,“w+”)
。注意
w+
。相关文档将为您完成您刚才指定的所有操作。将构造函数与filename@DanGetz我试过这个,结果和我之前试过的“w”@FelipeLema一样。你能澄清一下你的意思吗。我不知道SharedArrays可以解决我的问题。这看起来可以解决问题。当您以SharedArray的形式加载数据时,它是将数据加载到内存中,还是完全脱离磁盘工作?如果它完全在磁盘上工作,那么我认为将当前列提取到一个新变量中,以便在内存中处理它是最快的,对吗?我找不到任何文档来回答您的问题。另一方面,考虑到julia背后的理念,你只需尝试一下,然后根据我的想法进行分析/优化,这似乎正是我想要的。为了确保我理解您对字符串参数的看法,您是说使用
stream\u data=open(“data”,true,true,false,false,false)
而不是
stream\u data=open(“data”,“r+”)
将列写回二进制文件会更快吗?(和将列读入内存类似)
icol = 7
stream_data = open("data","r+")
position_data = 4*Nrow*(icol-1)
seek(stream_data,position_data)
write(stream_data,data_col)
close(stream_data)