Найти - Пользователи
Полная версия: Как увеличить скорость (оптимизировать) обработки большого файла
Начало » Python для новичков » Как увеличить скорость (оптимизировать) обработки большого файла
1
Seganapa
Всем доброго дня!
Уважаемые Питонщики, мне необходима Ваша помощь.

Имеется большой текстовый файл, размером 4Gb. В нем содержатся строки вида
sid0014 | http://gagaga.com/num=0310103&id=22556756 | pid=2346786
sid0048 | http://gagaga.com/num=045345345&id=22553425 | pid=567456
sid0093 | http://gagaga.com/num=126654&id=225534756 | pid=867546433
sid00235345634 | http://gagaga.com/num=0310103&id=22556756 | pid=3425457785343
….

Таких строк в файле более 4 млн. штук.
Мне нужно найти все строки с совпадающими ссылками и объединить первые и последние значения (разделитель “|”)

Например из строчек выше нужно получить
sid0014, sid00235345634 | http://gagaga.com/num=0310103&id=22556756 | pid=2346786, pid=3425457785343
т.к ссылка в верхней строке, совпадает с нижней.

В общем моих знаний питона хватило на то, чтобы написать цикл в цикле. Т.е. на каждой из 4 млн. строк (итераций) мне приходится пробегаться по всем строкам и выбирать нужные мне данные.

Немного оптимизировал код, теперь при каждой итерации я начинаю проход не с первой строки, а с предыдущей в первом цикле (т.е. отбрасываю то, что уже обработано). Но это не намного ускорило код.

Теперь подсчеты:
В среднем каждая моя итерация основного цикла обрабатывается 40 сек. Т.е. чтобы отработать 4 000 000 итераций мне нужно примерно 44 444 часов. (((

Докупил оперативки, думал загружать весь файл в список и потом с ним работать, но скорость почему-то не выросла. Вопрос - ПОЧЕМУ? Оперативки 8GB - файл 4GB.

Ребята, выручите! Как правильно устроить циклы для реальной работы. Т.к. Таких файлов у меня будет около 60 штук.
Заранее СПАСИБО!
doza_and
Seganapa
В общем моих знаний питона хватило на то, чтобы написать цикл в цикле
А написанный вами код где?
Непонятно куда вы потом данные деваете.
Непонятно что вы с файлами будете делать. Надо получить общий результат или отдельно по файлам?
Seganapa
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from grab import Grab
import re
from grab.selector import XpathSelector
from lxml.html import fromstring
import lxml.etree
from sys import stdin
f = open('/home/oleg/Рабочий стол/Parser/proba.csv')
output = open('/home/oleg/Рабочий стол/Parser/result.csv', 'w')	
filespisok = f.readlines()
f.close()
seen = []
for i, g in enumerate(filespisok):
	url = g.split("|")[1] 
	if seen.count(url) == 0:
		seen.append(url)
		taxonomy = []
		taxonomy2 = []
		for i1, g1 in enumerate(filespisok):
			if i1 >= i:
				if url == g1.split("|")[1]:
					if taxonomy.count(g1.split("|")[0]) == 0:
						taxonomy.append(g1.split("|")[0])
					if taxonomy2.count(g1.split("|")[2]) == 0:
						taxonomy2.append(g1.split("|")[2].replace("\n",""))
		stroka = g.split("|")
		taxonomy = '%s' % ','.join(taxonomy)
		taxonomy2 = '%s' % ','.join(taxonomy2)
		stroka[0] = taxonomy
		stroka[2] = taxonomy2
		
		stroka = '%s' % '|'.join(stroka)+'|\n'
		output.write(stroka)	
		
	#print ("Обработано строк: "+str(i+1))
output.close()

На выходе получаю файл со строками

sid0014 ,sid00235345634 | http://gagaga.com/num=0310103&id=22556756 | pid=2346786, pid=3425457785343|
sid0048 | http://gagaga.com/num=045345345&id=22553425 | pid=567456|
sid0093 | http://gagaga.com/num=126654&id=225534756 | pid=867546433|

Мне это и нужно, только ооооочень медленно работает. Как ускорить процесс?
Andrew_Lvov
Во первых, попробуйте без readlines:
for i, g in enumerate(f):

Во вторых, вы 4 раза делаете g1.split('|'). Выносите в переменную.

3. replace('\n', '') можно, я так понимаю, заменить на strip().

4. Ой мляяя, двойной цикл…… Квадратичная сложность. 16 000 000 000 000 итераций.

    urls = defaultdict(lambda: {'sid': set(), 'pid': set()})
    with open('proba.csv', 'r') as input_file:
        for k, s in enumerate(input_file):
            sid, url, pid = s.split(' | ')
            sid = sid.strip()
            url = url.strip()
            pid = pid.strip()
            selected = urls[url]
            selected['sid'].add(sid)
            selected['pid'].add(pid)
            if k % 65536 == 0:
                print('Processing line {}'.format(k))
    with open('result.csv', 'w') as outfile:
        for u, data in urls.items():
            outfile.write(' | '.join((','.join(data['sid']),
                                      u,
                                      ','.join(data['pid']))) + '\n')
Как-то так
Master_Sergius
Вам бы создать структуру дополнительную для хранения найденных ссылок, куда будете долепливать совпадения, таким образом, вам нужно будет пройтись по всему лишь единожды. Как ещё оптимизировать - пока что хз
Alen
Для таких ситуаций существует Pandas.
import pandas as pd
with open('bigdata.csv') as csv:
    raw_data = csv.read()
data = map(lambda x: x.split('|'), raw_data.split('\n'))
table = pd.DataFrame(data)
result = table.groupby(1).sum()
result.to_csv(path_or_buf='result.csv', sep='|' )
Seganapa
Спасибо огромное за советы! Очень помогли!
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB