如何处理1.61亿行的文件?

2024-06-17 09:02:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图处理这段代码,因为我有一个大文件,大小为3 GB“mydata.dat”,行数为161991000。代码用于使用DensityPeakCluster计算两点之间的距离。点数18000 文件的示例,如

1 2 26.23
1 3 44.49
1 4 47.17

等等,直到

1 18000 23.5

然后

2 3 25.2
2 4 15.2 

直到2 18000 0.25,依此类推直到17999 18000 0.25

代码的第一块是

class Graph(defaultdict):
     def __init__(self, input_file, sep=" ", header=False, undirect=True):

         super(Graph, self).__init__(dict)
         self.edges_num = 0
         with open(input_file) as f:
             if header:
                 f.readline()
             for line in f:
                 line = line.strip().split(sep)
                 self[line[0]][line[1]] = float(line[2])
                 self.edges_num += 1
                 if undirect:
                    self[line[1]][line[0]] = float(line[2])
                    self.edges_num += 1
   def edges(self):
        edges_list = []
        for node1 in self:
            for node2 in self[node1]:
                edges_list.append((node1, node2))
        return edges_list

代码块2,因为代码很长,所以要在这里编写它

    def edges_weight(self):
        weight_list = []
        for edge in self.edges():
            node1, node2 = edge
            weight_list.append([node1, node2, self[node1][node2]])
        weight_list = sorted(weight_list, key=lambda x:x[2])
        return weight_list
    def get_weight(self, node1, node2):
       return self[node1][node2]
    def get_weights(self):
        weights = []
        for edge in self.edges():
            weights.append(self.get_weight(edge[0], edge[1]))
        return weights
if __name__=="__main__":

    input_file = "./data/mydata.dat"
    percent = 2.0
    output_file = "./data/results"

    G = Graph(input_file)
    position = round(G.number_of_edges()*percent/100)
    dc = G.edges_weight()[position][2]
    print("average percentage of neighbours (hard coded): {}".format(percent))
    print("Computing Rho with gaussian kernel of radius: {}".format(dc))
    nodes = G.nodes()
    for i in range(G.number_of_nodes()-1):
        for j in range(i+1, G.number_of_nodes()):
            node_i = nodes[i]
            node_j = nodes[j]
            dist_ij = G.get_weight(node_i, node_j)

我怎么了

1-我得到了killed,所以我试图将读取文件作为

        bigfile = open(input_file,'r')
        tmp_lines = bigfile.readlines(1024*1024)
        for line in tmp_lines:
            line = line.strip().split(sep)
            self[line[0]][line[1]] = float(line[2])
            self.edges_num += 1
            if undirect:
               self[line[1]][line[0]] = float(line[2])
               self.edges_num += 1

2-但得到了

 dist_ij = G.get_weight(node_i, node_j) in get_weight
    return self[node1][node2]
 KeyError: '6336'

3-我尝试使用谷歌colab,但没有成功,因为RAM是12GB,对我来说不够。。我要求购买一个新的RAM,但问题仍然是我无法很好地管理代码,因此RAM的处理能力会降低。。我陷入了这个问题,不知道该怎么办

**1-我的问题是如何处理我的大文件?我应该用什么方法来处理这个尺寸

2-如果我使用NumPy加载文件,这会减少内存使用吗?**


Tags: 文件代码inselfnodeforgetline
1条回答
网友
1楼 · 发布于 2024-06-17 09:02:22

最直接的答案是不要一次加载整个文件。这甚至可以一次完成一行。例如,假设您想要求和:

filename = 'file.dat'
lines    = (int(line.split(' ')[2]) for line in open(filename)) 
print(sum(lines))

在这里,我们没有将所有的行加载到内存中。相反,我们打开了一个文件指针并启动了一个python生成器。生成器保存函数“int(line.split(“”)[2]),仅在调用每一行时执行该函数。需要调用每一行的启动由sum()启动,sum只会根据需要一次调用每一行,一次不会将多行加载到内存中。因此,当我们执行该行时,我们开始将来自生成器的行上的所有值相加,并保持一个运行总数。关键是代码不使用内存RAM(除了内核开销)

这也可以一次做一件。加载所有的零

filename = 'file.dat'
lines    = (line.split(' ') for line in open(filename))
zeros    = (line for line in lines if line[0]=='0' or line[1]=='0')
print(sum(c for a,b,c in zeros))

这当然比将部分或全部文件加载到内存中要慢。此外,你必须考虑你想在这样的文件上迭代多少次。最好只在这些行上迭代几次,收集所需的所有计算结果。然后,您可能希望保存这些答案,因为再次迭代文件需要更多时间

在考虑将文件加载到内存中时,需要仔细检查要加载的内容以及加载方式。例如,是否要在第1 2 26.23行中加载值1 2?如果没有,则将其去掉以占用更少的内存。比如说

import numpy as np

filename = 'file.dat'
values   = (float(line.split(' ')[2]) for line in open(filename))
X        = np.fromiter(values,dtype='float32',count=161991000)

通过指定计数,我们告诉python要预先分配多少内存(而不是让python在每次需要更多内存时重新调整数组)。有了这个大小的计数和float32的数据类型,我们知道这个数据将在RAM中占用647.97mb的空间。因此,请注意不要编写任何复制此数据的操作。如果你写的东西,使这5份副本,将消耗内存很快

我认为这会让您了解如何管理内存。:-)

相关问题 更多 >