2016-01-22 3 views
3

У меня есть файл словаря, который содержит слово в каждой строке.Замена строки с использованием словаря в python

названия-sorted.txt

a&a  
a&b  
a&c_bus  
a&e  
a&f  
a&m  
.... 

Для каждого слова, его номер строки идентификатор слова.

Тогда у меня есть другой файл, содержащий набор слов, разделенных вкладкой в ​​каждой строке.

a.txt

a_15 a_15_highway_(sri_lanka) a_15_motorway a_15_motorway_(germany) a_15_road_(sri_lanka) 

Я хотел бы заменить все слова по идентификатору, если он существует в словаре, так что результат выглядит,

3454 2345 123 5436  322 .... 

Так что я написал такая питон код, чтобы сделать это:

f = open("titles-sorted.txt") 
lines = f.readlines() 
titlemap = {} 
nr = 1 
for l in lines: 
    l = l.replace("\n", "") 
    titlemap[l.lower()] = nr 
    nr+=1 

fw = open("a.index", "w") 
f = open("a.txt") 
lines = f.readlines() 
for l in lines: 
    tokens = l.split("\t") 
    if tokens[0] in titlemap.keys(): 
      fw.write(str(titlemap[tokens[0]]) + "\t") 
      for t in tokens[1:]: 
        if t in titlemap.keys(): 
          fw.write(str(titlemap[t]) + "\t") 
      fw.write("\n") 

fw.close() 
f.close() 

Но этот код невероятно медленно, так что это делает меня подозрительным, если я сделал накануне Правильно.

Это эффективный способ сделать это?

+0

Сколько ключей есть, а затем сколько слов вы заменяете? – SirParselot

+1

одно дело в том, что вы вызываете 'readlines', вам это не нужно, и в зависимости от используемой версии python это может привести к немедленному чтению всего файла, что необязательно. вы можете просто использовать 'for l in f:' – njzk2

+0

Считаете ли вы использование потоков и рабочих? Должен ускорить его в разном количестве рабочих потоков. Обратите внимание: это не должно восприниматься как комментарий к алгоритму. Просто заявление о том, что больше работников делает для более быстрого завершения. – earnshae

ответ

1

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

Каждый раз, когда вы вызываете запись, некоторое количество вашего желаемого запроса на запись записывается в буфер, а затем после буфер заполнен, эта информация записывается в файл. Файл должен быть извлечен с вашего жесткого диска (поскольку он не существует в основной памяти). Поэтому ваш компьютер останавливается, пока он ждет несколько миллисекунд, которые требуется для извлечения блока из жесткого диска и записи на него. С другой стороны, вы можете выполнить синтаксический анализ строки и поиска на ваш хэш-файл за пару наносекунд, поэтому вы тратите много времени, ожидая завершения запроса на запись!

Вместо того чтобы писать немедленно, что если вы вместо этого сохранили список строк, которые вы хотели написать, а затем только написали их в конце, все подряд, или если вы обрабатываете огромный огромный файл, который превысит емкость вашей основной памяти, напишите ее, как только вы проанализировали определенное количество строк.

Это позволяет оптимизировать запись на диск, так как вы можете записывать несколько блоков за раз (это зависит от того, как Python и операционная система обрабатывают вызов записи).

4

Цикл записи содержит много вызовов write, которые обычно неэффективны. Вы, вероятно, может ускорить процесс, написав только один раз в каждой строке (или один раз в файл, если файл достаточно мал)

tokens = l.split("\t") 
fw.write('\t'.join(fw.write(str(titlemap[t])) for t in tokens if t in titlemap) 
fw.write("\n") 

или даже:

lines = [] 
for l in f: 
    lines.append('\t'.join(fw.write(str(titlemap[t])) for t in l.split('\t') if t in titlemap) 
fw.write('\n'.join(lines)) 

Кроме того, если используются ваши жетоны больше один раз, вы можете сэкономить время путем преобразования их в строку, когда вы читаете то:

titlemap = {l.strip().lower(): str(index) for index, l in enumerate(f, start=1)} 
0

Если мы применим эти предложения до сих пор и еще раз очистим ваш код (например, удалите ненужные вызовы .keys()), остается слишком медленным для ваших нужд?

title_map = {} 

token_file = open("titles-sorted.txt") 

for number, line in enumerate(token_file): 
    title_map[line.rstrip().lower()] = str(number + 1) 

token_file.close() 

input_file = open("a.txt") 
output_file = open("a.index", "w") 

for line in input_file: 
    tokens = line.split("\t") 

    if tokens[0] in title_map: 
     output_list = [title_map[tokens[0]]] 
     output_list.extend(title_map[token] for token in tokens[1:] if token in title_map) 
     output_file.write("\t".join(output_list) + "\n") 

output_file.close() 
input_file.close() 

Если это все-таки слишком медленно, дают нам немного больше данных для работы с включая оценку числа строк в каждом из ваших двух входных файлов.

+0

Удаление # вызовов fw.write() значительно снижает скорость, и теперь код работает очень быстро. Благодаря! Но я думал, что «токены [0] в title_map' и' tokens [0] в title_map.keys() 'эквивалентны. Является ли явно вызов ключей() более дорогим? – pandagrammer

+0

"in map" - поиск в режиме хэша. "в map.keys()" зависит от версии python. В Python 2 это линейный поиск списка. В Python 3 - это запрос к объекту dict_keys, который в лучшем случае является хэш-временем, но, возможно, чем-то меньшим. – cdlane

Смежные вопросы