Я реализую статистическую программу и создал узкое место производительности, и надеялся, что я смогу получить некоторую помощь от сообщества, чтобы, возможно, указать мне направление оптимизации.Python сравнивает каждую строку в файле со всеми остальными
Я создаю набор для каждой строки в файле и нахожу пересечение этого набора путем сравнения заданных данных каждой строки в одном файле. Затем я использую размер этого пересечения для фильтрации определенных наборов с выхода. Проблема в том, что у меня есть вложенный цикл (O (n)), а стандартный размер файлов, входящих в программу, составляет чуть более 20 000 строк. Я приурочил алгоритм и до 500 строк, он работает примерно через 20 минут, но для больших файлов требуется около 8 часов.
У меня есть 16 ГБ оперативной памяти и значительно быстрый 4-ядерный процессор Intel i7. Я не заметил существенных различий в использовании памяти, скопировав список1 и используя второй список для сравнения, вместо того, чтобы снова открывать файл (возможно, это потому, что у меня SSD?). Я думал, что механизм «с открытым» читает/записывает непосредственно на жесткий диск, который медленнее, но не заметил разницы при использовании двух списков. Фактически, программа редко использует более 1 ГБ ОЗУ во время работы.
Я надеюсь, что другие люди используют определенный тип данных или, возможно, лучше понимают многопроцессорность в Python и что они могут помочь мне ускорить процесс. Я ценю любую помощь, и я надеюсь, что мой код не слишком плохо написан.
import ast, sys, os, shutil
list1 = []
end = 0
filterValue = 3
# creates output file with filterValue appended to name
with open(arg2 + arg1 + "/filteredSets" + str(filterValue) , "w") as outfile:
with open(arg2 + arg1 + "/file", "r") as infile:
# create a list of sets of rows in file
for row in infile:
list1.append(set(ast.literal_eval(row)))
infile.seek(0)
for row in infile:
# if file only has one row, no comparisons need to be made
if not(len(list1) == 1):
# get the first set from the list and...
set1 = set(ast.literal_eval(row))
# ...find the intersection of every other set in the file
for i in range(0, len(list1)):
# don't compare the set with itself
if not(pos == i):
set2 = list1[i]
set3 = set1.intersection(set2)
# if the two sets have less than 3 items in common
if(len(set3) < filterValue):
# and you've reached the end of the file
if(i == len(list1)):
# append the row in outfile
outfile.write(row)
# increase position in infile
pos += 1
else:
break
else:
outfile.write(row)
ввода образца будет файл с этим форматом:
[userID1, userID2, userID3]
[userID5, userID3, userID9]
[userID10, userID2, userID3, userID1]
[userID8, userID20, userID11, userID1]
Выходной файл, если это было входной файл будет:
[userID5, userID3, userID9]
[userID8, userID20, userID11, userID1]
... потому что два снятых набора содержали три или более одинаковых идентификатора пользователя.
Если ваша оперативная память значительно больше вашего файла, ОС * может * кэшировать файл в ОЗУ. Невозможно контролировать это разумным способом. Это происходит автоматически без запроса Python. – Kevin
Наверное, не изменится, но почему вы открываете/файл дважды? – madprops
Возможно, вам не потребуется дважды читать файл. Вы должны взглянуть на itertools.permutations, чтобы получить наборы сравнения из первого списка (https://docs.python.org/2/library/itertools.html#itertools.permutations) ' – Obsidian