首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从随机选择的文本文件中抽取单词

从随机选择的文本文件中抽取单词
EN

Code Review用户
提问于 2017-03-07 09:44:09
回答 2查看 481关注 0票数 3

我开发了一个脚本,可以从.txt文件列表中随机选择50个元素。这个过程重复100次。脚本将随机选择的文本文件连接到一个长字符串中,然后过滤出最长的子字符串。

我想在数字海洋上的一个水滴上运行这个脚本。但是,服务器会杀死脚本。当我随机选择3个元素时,它就能工作了。我没记忆了吗?我如何处理这个问题呢?

这是文件我随机选择项目。这是我的密码:

代码语言:javascript
复制
# coding: utf-8

import glob
from collections import Counter
import pickle
import random

de_list_soz = pickle.load(open('de_list_soz.p', 'rb'))
str_seq_list = []

for str_seq in range(0,100):  
    #creating random list
    random_list = []
    for item in range(0,50):
       list_item = random.choice(de_list_soz)
       random_list.append(list_item)

    #creating long string
    long_str = ''
    for de in random_list:

        input_file = open('txt_sr_de/txt_sr_de/' + de, 'r')
        text = input_file.read()
        text = text.replace('\n', ' ').replace('\xa0', '').replace('  ', '')
        #Removing these automated notifications
        text = text.replace('Wichtiger Hinweis:Diese Website wird in älteren Versionen von Netscape ohne graphische Elemente dargestellt. Die Funktionalität der Website ist aber trotzdem gewährleistet. Wenn Sie diese Website regelmässig benutzen, empfehlen wir Ihnen, auf Ihrem Computer einen aktuellen Browser zu installieren.Zurück zur Einstiegsseite Drucken Grössere Schrift', '')
        text = text.replace('Vorwärts ähnliche Leitentscheide suchenähnliche Urteile ab 2000 suchen Drucken nach oben', '')
        text = text.replace('Bundesgericht Tribunal fédéral Tribunale federale Tribunal federal', '')
        text = text.replace('Navigation Neue Suche Zurück zum Suchresultat Rang: Zurück 180', '')
        text = text.replace('Navigation Neue Suche Zurück zum Suchresultat Rang:1 ähnliche Leitentscheide suchenähnliche Urteile ab 2000 suchen Drucken nach oben', '')
        text = text.replace('  ', ' ')

        long_str = long_str + text

    times=3

    for n in range(1,int(len(long_str)/times+1)):
        substrings=[long_str[i:i+n] for i in range(len(long_str)-n+1)]
        freqs=Counter(substrings)
        if freqs.most_common(1)[0][1]<3:
            n-=1
            break
        else:
            seq=freqs.most_common(1)[0][0]


    str_seq_list.append(seq)


pickle.dump(str_seq_list, open('SOZIALRECHT_DE.p', 'wb'))
EN

回答 2

Code Review用户

发布于 2017-03-07 14:33:19

由于您的代码同时执行多个操作,因此您应该将其拆分为函数以提高可读性。第一次天真的重写会产生以下结果:

代码语言:javascript
复制
from collections import Counter
import random


def filter_text(text):
    return (text
            .replace('\n', ' ')
            .replace('\xa0', '')
            .replace('  ', '')
            #Removing these automated notifications
            .replace('Wichtiger Hinweis:Diese Website wird in älteren Versionen von Netscape ohne graphische Elemente dargestellt. Die Funktionalität der Website ist aber trotzdem gewährleistet. Wenn Sie diese Website regelmässig benutzen, empfehlen wir Ihnen, auf Ihrem Computer einen aktuellen Browser zu installieren.Zurück zur Einstiegsseite Drucken Grössere Schrift', '')
            .replace('Vorwärts ähnliche Leitentscheide suchenähnliche Urteile ab 2000 suchen Drucken nach oben', '')
            .replace('Bundesgericht Tribunal fédéral Tribunale federale Tribunal federal', '')
            .replace('Navigation Neue Suche Zurück zum Suchresultat Rang: Zurück 180', '')
            .replace('Navigation Neue Suche Zurück zum Suchresultat Rang:1 ähnliche Leitentscheide suchenähnliche Urteile ab 2000 suchen Drucken nach oben', '')
            .replace('  ', ' '))


def create_string_from_files(files, root='txt_sr_de/txt_sr_de', sample=50):
    #creating random list
    random_list = []
    for item in range(sample):
       list_item = random.choice(files)
       random_list.append(list_item)

    #creating long string
    long_str = ''
    for de in random_list:

        input_file = open(os.path.join(root, de), 'r')
        text = input_file.read()

        long_str = long_str + filter_text(text)
    return long_str


def extract_most_common_sequence(text, minimum_occurences=3, times=3):
    for n in range(1,int(len(text)/times+1)):
        substrings=[text[i:i+n] for i in range(len(text)-n+1)]
        freqs=Counter(substrings)
        if freqs.most_common(1)[0][1] < minimum_occurences:
            n-=1
            return seq
        else:
            seq=freqs.most_common(1)[0][0]


def main(files, repeat=100):
    str_seq_list = []

    for str_seq in range(repeat):  
        long_str = create_string_from_files(files)
        str_seq_list.append(extract_most_common_sequence(long_str))

    return str_seq_list


if __name__ == '__main__':
    import pickle
    de_list_soz = pickle.load(open('de_list_soz.p', 'rb'))
    str_seq_list = main(de_list_soz)
    pickle.dump(str_seq_list, open('SOZIALRECHT_DE.p', 'wb'))

现在我们可以开始清理了。

create_string_from_files中,您基本上是在重新发明random.sample

代码语言:javascript
复制
>>> import random
>>> random.sample('abcdefghi', 4)
['h', 'e', 'c', 'f']

您也碰巧遇到了open文件,但从未关闭它们:使用with语句自动处理这些文件。

最后,手工连接长句并不是有效的记忆。现在,让我们请求str.join为我们做这件事。但为了更好地完成这一任务,我们需要进一步拆分函数:

代码语言:javascript
复制
def read_and_filter_file(filename):
    with open(filename) as input_file:
        text = input_file.read()
    return filter_text(text)


def create_string_from_files(files, root='txt_sr_de/txt_sr_de', samples=50):
    return ''.join(
        read_and_filter_file(os.path.join(root, de))
        for de in random.sample(files, samples)
    )

通过将“创建空列表+ for循环+ append”模板替换为更有效的列表理解,可以对主要功能进行类似的改进:

代码语言:javascript
复制
def main(files, repeat=100):
    return [
        extract_most_common_sequence(create_string_from_files(files))
        for _ in range(repeat)
    ]

extract_most_common_sequence函数也可以使用一些迭代工具配方进行优化。我正在考虑pairwise配方的一个变化,因为您的列表理解,n是2差不多就是了。即使用:

代码语言:javascript
复制
>>> long_str = 'This is a test'
>>> n = 2
>>> [long_str[i:i+n] for i in range(len(long_str)-n+1)]
['Th', 'hi', 'is', 's ', ' i', 'is', 's ', ' a', 'a ', ' t', 'te', 'es', 'st']
>>> n = 4
>>> [long_str[i:i+n] for i in range(len(long_str)-n+1)]
['This', 'his ', 'is i', 's is', ' is ', 'is a', 's a ', ' a t', 'a te', ' tes', 'test']

所以用这样的方法:

代码语言:javascript
复制
def tuplewise(iterable, length):
    tees = itertools.tee(iterable, length)
    for i, t in enumerate(tees):
        for _ in xrange(i):
            next(t, None)
    return itertools.izip(*tees)

用于Python 2或:

代码语言:javascript
复制
def tuplewise(iterable, length):
    tees = itertools.tee(iterable, length)
    for i, t in enumerate(tees):
        for _ in range(i):
            next(t, None)
    return zip(*tees)

对于Python 3,您可以简化写操作,并节省一些内存使用,如下所示:

代码语言:javascript
复制
def extract_most_common_sequence(text, minimum_occurences=3, times=3):
    sequence = ''
    for n in range(1, int(len(text)/times+1)):
        freqs = Counter(tuplewise(text, n))
        (most_frequent, higher_frequency), = freqs.most_common(1)
        if higher_frequency < minimum_occurences:
            break
        sequence = ''.join(most_frequent)
    return sequence

现在,我将sequence = ''定义为一种安全措施,在不太可能出现文本很短的情况下,“否”字母会出现两次以上。它只是让函数在每一种情况下都返回一些东西。

既然代码的可读性更强,让我们来解决您的内存问题。

需要注意的是,在内存中的单个字符串中聚合50个文件的内容可能会导致崩溃。因此,让我们使用一些磁盘存储。为此,我们将使用tempfile模块。这样做的目的是将过滤过的文本存储到一个文件中,并读取该文件(一遍又一遍),以获得所需的最常见的序列。因此,我们需要对tuplewise进行一点调整,要么一次读取一个字符,然后按请求的大小读取yield单词,或者更好的是,就I/O而言,反复读取一个固定大小的数据块,然后逐个从其中获取字符,以生成所需大小的单词:

代码语言:javascript
复制
import os
import random
import itertools
import tempfile
from collections import Counter


def filter_text(text):
    return (text
            .replace('\n', ' ')
            .replace('\xa0', '')
            .replace('  ', '')
            #Removing these automated notifications
            .replace('Wichtiger Hinweis:Diese Website wird in älteren Versionen von Netscape ohne graphische Elemente dargestellt. Die Funktionalität der Website ist aber trotzdem gewährleistet. Wenn Sie diese Website regelmässig benutzen, empfehlen wir Ihnen, auf Ihrem Computer einen aktuellen Browser zu installieren.Zurück zur Einstiegsseite Drucken Grössere Schrift', '')
            .replace('Vorwärts ähnliche Leitentscheide suchenähnliche Urteile ab 2000 suchen Drucken nach oben', '')
            .replace('Bundesgericht Tribunal fédéral Tribunale federale Tribunal federal', '')
            .replace('Navigation Neue Suche Zurück zum Suchresultat Rang: Zurück 180', '')
            .replace('Navigation Neue Suche Zurück zum Suchresultat Rang:1 ähnliche Leitentscheide suchenähnliche Urteile ab 2000 suchen Drucken nach oben', '')
            .replace('  ', ' '))


def read_and_filter_file(filename):
    with open(filename) as input_file:
        text = input_file.read()
    return filter_text(text)


def create_string_from_files(output, files, root='txt_sr_de/txt_sr_de', samples=50):
    for filename in random.sample(files, samples):
        output.write(read_and_filter_file(os.path.join(root, filename)))


def read_chunks(file_object, chunk_size, block_size=4096):
    word = file_object.read(chunk_size)
    yield word
    while True:
        data = file_object.read(block_size)
        if not data:
            return
        for character in data:
            # Drop first character and append the next one
            word = word[1:] + character
            yield word


def extract_most_common_sequence(input_file, minimum_occurences=3, times=3):
    input_file.seek(0, os.SEEK_END)
    file_size = input_file.tell()
    sequence = ''

    for n in range(1, int(file_size/times+1)):
        input_file.seek(0)  # Be sure to read the whole file each time
        freqs = Counter(read_chunks(input_file, n))
        (most_frequent, higher_frequency), = freqs.most_common(1)
        if higher_frequency < minimum_occurences:
            break
        sequence = most_frequent
    return sequence


def main(files):
    with tempfile.NamedTemporaryFile(mode='w+') as storage:
        create_string_from_files(storage, files)
        return extract_most_common_sequence(storage)


if __name__ == '__main__':
    import pickle
    de_list_soz = pickle.load(open('de_list_soz.p', 'rb'))
    str_seq_list = [main(de_list_soz) for _ in range(100)]
    pickle.dump(str_seq_list, open('SOZIALRECHT_DE.p', 'wb'))

我将main更改为返回单个元素,而不是返回整个列表,因为使用此实现感觉更清晰。所有重复的事情现在都在测试代码中完成。

票数 2
EN

Code Review用户

发布于 2017-03-07 14:52:17

我只是重写了您搜索最长子字符串的方式,老实说,我并不完全理解您在代码中尝试了什么,但是从我的perspectiv来看,这是您的内存消失的地方。我还添加了一些内容,你应该看看它们是如何工作的,也遵循你的问题评论中的链接。

在此代码中,子字符串以空格“”或行中断"\n“结尾。

代码语言:javascript
复制
import pickle
import random


def longest_substring(s: str) -> str:

    indx = 0
    lngth = 0

    tmpindx = 0
    tmplngth = 0

    for i, c in enumerate(s):

        if c == " " | c == "\n":

            if tmplngth > lngth:
                lngth = tmplngth
                indx = tmpindx

            tmplngth = 0
            tmpindx = i + 1

        else:
            tmplngth += 1

    return s[indx: indx + lngth]


with open('de_list_soz.p', 'rb') as o:
    de_list_soz = pickle.load(o)

str_seq_list = []

for str_seq in range(0, 100):
    # creating random list
    random_list = []
    for item in range(0, 50):
        list_item = random.choice(de_list_soz)
        random_list.append(list_item)

    # creating long string
    long_str = ''

    for de in random_list:

        with open('txt_sr_de/txt_sr_de/' + de, 'r') as input_file:
            text = input_file.read()

        text = text.replace('\n', ' ').replace('\xa0', '').replace('  ', '')
        # Removing these automated notifications
        text = text.replace('Wichtiger Hinweis:Diese Website wird in älteren Versionen von Netscape ohne graphische Elemente dargestellt. Die Funktionalität der Website ist aber trotzdem gewährleistet. Wenn Sie diese Website regelmässig benutzen, empfehlen wir Ihnen, auf Ihrem Computer einen aktuellen Browser zu installieren.Zurück zur Einstiegsseite Drucken Grössere Schrift', '')
        text = text.replace('Vorwärts ähnliche Leitentscheide suchenähnliche Urteile ab 2000 suchen Drucken nach oben', '')
        text = text.replace('Bundesgericht Tribunal fédéral Tribunale federale Tribunal federal', '')
        text = text.replace('Navigation Neue Suche Zurück zum Suchresultat Rang: Zurück 180', '')
        text = text.replace('Navigation Neue Suche Zurück zum Suchresultat Rang:1 ähnliche Leitentscheide suchenähnliche Urteile ab 2000 suchen Drucken nach oben', '')
        text = text.replace('  ', ' ')

        long_str += text

    # here wo go search longest substring
    long_sub = longest_substring(long_str)

    # here we remove all occurrence of longest substring
    no_long_sub_long_str = long_str.replace(long_sub, "")

with open('SOZIALRECHT_DE.p', 'wb') as o:
    pickle.dump(str_seq_list, o)
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/157132

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档