Оптимизация функции с помощью словаря и Zip () - PullRequest
0 голосов
/ 10 января 2011

У меня есть следующая функция:

def filetxt():
    word_freq = {}
    lvl1      = []
    lvl2      = []
    total_t   = 0
    users     = 0
    text      = []

    for l in range(0,500):
        # Open File
        if os.path.exists("C:/Twitter/json/user_" + str(l) + ".json") == True:
            with open("C:/Twitter/json/user_" + str(l) + ".json", "r") as f:
                text_f = json.load(f)
                users = users + 1
                for i in range(len(text_f)):
                    text.append(text_f[str(i)]['text'])
                    total_t = total_t + 1
        else:
            pass

    # Filter
    occ = 0
    import string
    for i in range(len(text)):
        s = text[i] # Sample string
        a = re.findall(r'(RT)',s)
        b = re.findall(r'(@)',s)
        occ = len(a) + len(b) + occ
        s = s.encode('utf-8')
        out = s.translate(string.maketrans("",""), string.punctuation)


        # Create Wordlist/Dictionary
        word_list = text[i].lower().split(None)

        for word in word_list:
            word_freq[word] = word_freq.get(word, 0) + 1

        keys = word_freq.keys()

        numbo = range(1,len(keys)+1)
        WList = ', '.join(keys)
        NList = str(numbo).strip('[]')
        WList = WList.split(", ")
        NList = NList.split(", ")
        W2N = dict(zip(WList, NList))

        for k in range (0,len(word_list)):
            word_list[k] = W2N[word_list[k]]
        for i in range (0,len(word_list)-1):
            lvl1.append(word_list[i])
            lvl2.append(word_list[i+1])

Я использовал профилировщик, чтобы выяснить, что наибольшее время ЦП затрачивается на функции zip() и части кода join и split, я смотрю, есть ли способ Я упустил из виду, что мог бы потенциально очистить код, чтобы сделать его более оптимизированным, поскольку наибольшая задержка, по-видимому, связана с работой со словарями и функцией zip(). Любая помощь будет оценена спасибо!

p.s. Основное назначение этой функции заключается в том, что я загружаю файлы, содержащие около 20 твитов, поэтому я, скорее всего, получу около 20–50 тыс. Файлов, отправляемых через эту функцию. В результате я создаю список всех отдельных слов в твите, за которыми следуют слова, связанные с чем, например:

1 "love"
2 "pasa"
3 "mirar"
4 "ants"
5 "kers"
6 "morir"
7 "dreaming"
8 "tan"
9 "rapido"
10 "one"
11 "much"
12 "la"
...
10 1
13 12
1 7
12 2
7 3
2 4
3 11
4 8
11 6
8 9
6 5
9 20
5 8
20 25
8 18
25 9
18 17
9 2
...

Ответы [ 3 ]

2 голосов
/ 10 января 2011

Я думаю вы хотите что-то вроде:

import string
from collections import defaultdict
rng = xrange if xrange else range

def filetxt():
    users     = 0
    total_t   = 0
    occ       = 0

    wordcount = defaultdict(int)
    wordpairs = defaultdict(lambda: defaultdict(int))
    for filenum in rng(500):
        try:
            with open("C:/Twitter/json/user_" + str(filenum) + ".json",'r') as inf:
                users += 1
                tweets = json.load(inf)
                total_t += len(tweets)

                for txt in (r['text'] for r in tweets):
                    occ += txt.count('RT') + txt.count('@')
                    prev = None
                    for word in txt.encode('utf-8').translate(None, string.punctuation).lower().split():
                        wordcount[word] += 1
                        wordpairs[prev][word] += 1
                        prev = word
        except IOError:
            pass
1 голос
/ 10 января 2011

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

from itertools import izip
def filetxt():
    # keeps track of word count for each word.
    word_freq = {}
    # list of words which we've found
    word_list = []
    # mapping from word -> index in word_list
    word_map  = {}
    lvl1      = []
    lvl2      = []
    total_t   = 0
    users     = 0
    text      = []

    ####### You should replace this with a glob (see: glob module)
    for l in range(0,500):
        # Open File
        try:
            with open("C:/Twitter/json/user_" + str(l) + ".json", "r") as f:
                text_f = json.load(f)
                users = users + 1
                # in this file there are multiple tweets so add the text
                # for each one.
                for t in text_f.itervalues():
                    text.append(t)  ## CHECK THIS
        except IOError:
            pass

    total_t = len(text)
    # Filter
    occ = 0
    import string
    for s in text:
        a = re.findall(r'(RT)',s)
        b = re.findall(r'(@)',s)
        occ += len(a) + len(b)
        s = s.encode('utf-8')
        out = s.translate(string.maketrans("",""), string.punctuation)


        # make a list of words that are in the text s
        words = s.lower().split(None)

        for word in word_list:
            # try/except is quicker when we expect not to miss
            # and it will be rare for us not to have
            # a word in our list already.
            try:
                word_freq[word] += 1
            except KeyError:
                # we've never seen this word before so add it to our list
                word_freq[word] = 1
                word_map[word] = len(word_list)
                word_list.append(word)


        # little trick to get each word and the word that follows
        for curword, nextword in zip(words, words[1:]):
            lvl1.append(word_map[curword])
            lvl2.append(word_map[nextword])

Что собирается сделать, это дать вам следующее. lvl1 выдаст вам список чисел, соответствующих словам в word_list. поэтому word_list[lvl1[0]] будет первым словом в первом твите, который вы обработали. lvl2[0] будет индексом слова, следующего за lvl1[0], так что вы можете сказать, world_list[lvl2[0]] - это слово, которое follows word_list[lvl1[0]]. Этот код в основном поддерживает word_map, word_list и word_freq при его создании.

Обратите внимание, что способ, которым вы делали это раньше, в частности способ, которым вы создавали W2N, будет , а не , работать должным образом. Словари не поддерживают порядок. Заказанные словари появятся в 3.1, но пока забудем об этом. В основном, когда вы делали word_freq.keys(), оно менялось каждый раз, когда вы добавляли новое слово, поэтому не было последовательности. Посмотрите этот пример,

>>> x = dict()
>>> x[5] = 2
>>> x
{5: 2}
>>> x[1] = 24
>>> x
{1: 24, 5: 2}
>>> x[10] = 14
>>> x
{1: 24, 10: 14, 5: 2}
>>>

Итак, 5 раньше было вторым, а теперь третьим.

Я также обновил его, чтобы использовать индекс 0 вместо 1 индекса. Я не знаю, почему вы использовали range(1, len(...)+1), а не просто range(len(...)).

В любом случае, вам не следует думать о циклах for в традиционном смысле C / C ++ / Java, где вы делаете циклы над числами. Вам следует учитывать, что если вам не нужен индексный номер, он вам не нужен.

Полезное правило: если вам нужен индекс, вам, вероятно, нужен элемент с этим индексом, и вы все равно должны использовать enumerate. LINK

Надеюсь, это поможет ...

0 голосов
/ 10 января 2011

Несколько вещей.Эти строки странны для меня, если их объединить:

WList = ', '.join(keys)
<snip>
WList = WList.split(", ")

Это должно быть Wlist = list(keys).

Вы уверены, что хотите оптимизировать это?Я имею в виду, это действительно так медленно, что стоит вашего времени?И, наконец, было бы здорово описать, что должен делать скрипт, вместо того, чтобы позволить нам расшифровать его из кода:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...