Как быстро создать словарь из списка строк в python - PullRequest
0 голосов
/ 14 марта 2020

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

  • Слово, если это слово появляется 5 или более раз в этом списке
  • Простой идентификатор для этого слова

Поэтому мой словарь в словаре python будет содержать слово: id записей

Во-первых, у меня есть вспомогательная функция для деления строка в токены, или слова

def split_sentence(sentence):
    return list(filter(lambda x: len(x) > 0, re.split('\W+', sentence.lower())))

Затем я сгенерирую словарь, который работает следующим образом:

def generate_vocabulary(train_captions):
    """
    Return {token: index} for all train tokens (words) that occur 5 times or more, 
        `index` should be from 0 to N, where N is a number of unique tokens in the resulting dictionary.
    """  
    #convert the list of whole captions to one string
    string=listToStr = ' '.join([str(elem) for elem in train_captions]) 

    #divide the string tokens (individual words), by calling the previous function 
    individual_words=split_sentence(string)

    #create a list of words that happen 5 times or more in that string  
    more_than_5=list(set([x for x in individual_words if individual_words.count(x) >= 5]))

    #generate ids
    ids=[i for i in range(0,len(more_than_5))] 

    #generate the vocabulary(dictionary)
    vocab = dict(zip(more_than_5,ids))

    return {token: index for index, token in enumerate(sorted(vocab))}  

Код работает как шарм для относительно небольших списков подписей. Однако со списками с тысячами длин (например, 80000) это длится вечно. Я запускаю этот код в течение часа.

Есть ли способ ускорить мой код? Как я могу вычислить мою переменную more_than_5 быстрее?

РЕДАКТИРОВАТЬ: я забыл упомянуть, что в очень немногих указанных c членах этого списка строк есть символы \ n только в некоторых элементах в начале предложения. Можно ли удалить только этот символ из моего списка, а затем снова применить алгоритм?

Ответы [ 2 ]

1 голос
/ 14 марта 2020

Как сказал @ Эдуард Ильясов, класс Counter является лучшим, когда нужно считать вещи.

Вот мое решение:

import re
import collections

original_text = (
    "I say to you today, my friends, though, even though ",
    "we face the difficulties of today and tomorrow, I still have ",
    "a dream. It is a dream deeply rooted in the American ",
    "dream. I have a dream that one day this nation will rise ",
    'up, live out the true meaning of its creed: "We hold these ',
    'truths to be self-evident, that all men are created equal."',
    "",
    "I have a dream that one day on the red hills of Georgia ",
    "sons of former slaves and the sons of former slave-owners ",
    "will be able to sit down together at the table of brotherhood. ",
    "I have a dream that one day even the state of ",
    "Mississippi, a state sweltering with the heat of injustice, ",
    "sweltering with the heat of oppression, will be transformed ",
    "into an oasis of freedom and justice. ",
    "",
    "I have a dream that my four little chi1dren will one day ",
    "live in a nation where they will not be judged by the color ",
    "of their skin but by the content of their character. I have ",
    "a dream… I have a dream that one day in Alabama, ",
    "with its vicious racists, with its governor having his lips ",
    "dripping with the words of interposition and nullification, ",
    "one day right there in Alabama little black boys and black ",
    "girls will he able to join hands with little white boys and ",
    "white girls as sisters and brothers. "
    )

def split_sentence(sentence):
    return (x.lower() for x in re.split('\W+', sentence.strip()) if x)

def generate_vocabulary(train_captions):
    word_count = collections.Counter()

    for current_sentence in train_captions:
        word_count.update(split_sentence(str(current_sentence)))

    return {key: value for (key, value) in word_count.items() if value >= 5}

print(generate_vocabulary(original_text))

Я сделал несколько предположений что вы не указали:

  • Я не думал, что слово будет занимать два предложения
  • Я сохранил тот факт, что ваши заголовки не всегда будут строками. Если вы знаете, что они всегда будут, вы можете просто код, изменив word_count.update(split_sentence(str(current_sentence))) на word_count.update(split_sentence(current_sentence))
1 голос
/ 14 марта 2020

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

import re
from collections import Counter

def split_sentence(sentence):
    return list(filter(lambda x: len(x) > 0, re.split('\W+', sentence.lower())))

def generate_vocabulary(train_captions, min_threshold):
    """
    Return {token: index} for all train tokens (words) that occur min_threshold times or more, 
        `index` should be from 0 to N, where N is a number of unique tokens in the resulting dictionary.
    """  
    #convert the list of whole captions to one string
    concat_str = ' '.join([str(elem).strip('\n') for elem in train_captions]) 
    #divide the string tokens (individual words), by calling the split_sentence function 
    individual_words = split_sentence(concat_str)
    #create a list of words that happen min_threshold times or more in that string  
    condition_keys = sorted([key for key, value in Counter(individual_words).items() if value >= min_threshold])
    #generate the vocabulary(dictionary)
    result = dict(zip(condition_keys, range(len(condition_keys))))
    return result

train_captions = ['Nory was a Catholic because her mother was a Catholic, and Nory’s mother was a Catholic because her father was a Catholic, and her father was a Catholic because his mother was a Catholic, or had been.',
                  'I felt happy because I saw the others were happy and because I knew I should feel happy, but I wasn’t really happy.',
                  'Almost nothing was more annoying than having our wasted time wasted on something not worth wasting it on.']

generate_vocabulary(train_captions, min_threshold=5)
# {'a': 0, 'because': 1, 'catholic': 2, 'i': 3, 'was': 4} 
...