7

Python'da yeni ve şu anda Python 2 kullanıyorum. Her biri çok büyük miktarda veri içeren bazı kaynak dosyalarım var (yaklaşık 19 milyon satır)).python - büyük dosya arama verimliliğini artırarak artırın (boyut)

apple \t N \t apple 
n&apos 
garden \t N \t garden 
b\ta\md 
great \t Adj \t great 
nice \t Adj \t (unknown) 
etc 

Benim görevim bir hedef kelime 10 kelime önce ve bu kelimeden sonra korpus bulunan bazı hedef kelime ve her seferinde her dosyanın 3 sütun arama yapmaktır gelmiş olması: Aşağıdaki benziyor çok boyutlu bir sözlüğe eklendi.

EDIT: '&', '\' veya '(bilinmeyen)' dizgisini içeren satırlar dışlanmalıdır.

Bunu, aşağıdaki kodda gördüğünüz gibi readlines() ve numaralandır() kullanarak çözmeye çalıştım. Kod, gerekeni yapar ama kaynak dosyasında sağlanan veri miktarı için yeterince verimli değildir.

Tüm dosyaları belleğe yüklediğinden, büyük veri kümeleri için readlines() veya read() işlevinin kullanılmaması gerektiğini biliyorum. Bununla birlikte, dosya satırını okuyarak, 10 kelimeyi hedef kelimeden önce ve sonra almak için numaralandırma yöntemini kullanmadım. Ayrıca, bu dosyada kullanma iznim olmadığı için mmap kullanamıyorum.

Yani, bazı boyut sınırlamaları olan readlines yönteminin en verimli çözüm olacağını düşünüyorum. Bununla birlikte, bunun için kod, sadece sözcük kırılırken, hedef kelimenin yakalanmayacağı 10 kelimeden sonuna kadar geçen süre kadar, bazı hatalar yapmaz mıyım? o çıkarılan tüm bilgilerin dışarı çok boyutlu bir sözlük yaratır ve sonra bir csv dosyası yazar bir fonksiyonun bir parçası olarak

def get_target_to_dict(file): 
targets_dict = {} 
with open(file) as f: 
    for line in f: 
      targets_dict[line.strip()] = {} 
return targets_dict 

targets_dict = get_target_to_dict('targets_uniq.txt') 
# browse directory and process each file 
# find the target words to include the 10 words before and after to the dictionary 
# exclude lines starting with <,-,; to just have raw text 

    def get_co_occurence(path_file_dir, targets, results): 
     lines = [] 
     for file in os.listdir(path_file_dir): 
      if file.startswith('corpus'): 
      path_file = os.path.join(path_file_dir, file) 
      with gzip.open(path_file) as corpusfile: 
       # PROBLEMATIC CODE HERE 
       # lines = corpusfile.readlines() 
       for line in corpusfile: 
        if re.match('[A-Z]|[a-z]', line): 
         if '(unknown)' in line: 
          continue 
         elif '\\' in line: 
          continue 
         elif '&' in line: 
          continue 
         lines.append(line) 
       for i, line in enumerate(lines): 
        line = line.strip() 
        if re.match('[A-Z][a-z]', line): 
         parts = line.split('\t') 
         lemma = parts[2] 
         if lemma in targets: 
          pos = parts[1] 
          if pos not in targets[lemma]: 
           targets[lemma][pos] = {} 
          counts = targets[lemma][pos] 
          context = [] 
          # look at 10 previous lines 
          for j in range(max(0, i-10), i): 
           context.append(lines[j]) 
          # look at the next 10 lines 
          for j in range(i+1, min(i+11, len(lines))): 
           context.append(lines[j]) 
          # END OF PROBLEMATIC CODE 
          for context_line in context: 
           context_line = context_line.strip() 
           parts_context = context_line.split('\t') 
           context_lemma = parts_context[2] 
           if context_lemma not in counts: 
            counts[context_lemma] = {} 
           context_pos = parts_context[1] 
           if context_pos not in counts[context_lemma]: 
            counts[context_lemma][context_pos] = 0 
           counts[context_lemma][context_pos] += 1 
       csvwriter = csv.writer(results, delimiter='\t') 
       for k,v in targets.iteritems(): 
        for k2,v2 in v.iteritems(): 
         for k3,v3 in v2.iteritems(): 
          for k4,v4 in v3.iteritems(): 
           csvwriter.writerow([str(k), str(k2), str(k3), str(k4), str(v4)]) 
           #print(str(k) + "\t" + str(k2) + "\t" + str(k3) + "\t" + str(k4) + "\t" + str(v4)) 

results = open('results_corpus.csv', 'wb') 
word_occurrence = get_co_occurence(path_file_dir, targets_dict, results) 

Ben bütünlük adına kod bütün bölümünü kopyaladı.

Gerçekten bu kod daha verimli hale getirmek için herhangi bir ipucu veya öneri takdir ediyorum. Benim fikrim 10 satır ve sonrasında saklamak için başka tampon önce saklamak için bir tampon oluşturmaktı

+0

"map", "filter", "groupby" ve "islice" –

+0

'u verimli bir şekilde kullanarak yapabilirsiniz. Teşekkürler, bunu okudum ve çok verimli görünüyor. Yukarıdaki kodla ilgili biraz daha detaylandırır mısınız? 'Map' kullanmak için, kesinlikle listelemek için corpusfile'a ihtiyacım var, değil mi? –

+0

Sütunda 10 kelime veya 10 kelime daha buluyor musunuz? –

cevap

3

tam 10 kelime önce ve hedef sözcükten sonra dikkate alır, böylece

DÜZENLEME Ben, kod düzeltilmiş 10 satır, okunmakta olan dosya olarak, tamponun içine itilir ve sonraki arabellek için boyut 10

'u aşarsa tampon açılır, iterator 1 dosyasından başka bir yineleyici kopyaladım. Daha sonra her iki yineleyici, 10 satırdan sonra almak için 10 yineleme çalıştıran klon yineleyici ile döngü içinde paralel olarak çalışır.

readlines kullanılarak bu önlemek() ve bellekte tüm dosya yükleyin. o

düzenlenmiş fiili durumda sizin için çalışan Umut: sadece doldurmadan önce sütun 3 değil '&', '\', '(bilinmiyor)' de değişim birini içeriyorsa eğer tampon sonra. sadece bölünmüş içine bölünmüş ('\ t')() bu yüzden tüm boşlukları veya sekme

import itertools 
def get_co_occurence(path_file_dir, targets, results): 
    excluded_words = ['&', '\\', '(unknown)'] # modify excluded words here 
    for file in os.listdir(path_file_dir): 
     if file.startswith('testset'): 
      path_file = os.path.join(path_file_dir, file) 
      with open(path_file) as corpusfile: 
       # CHANGED CODE HERE 
       before_buf = [] # buffer to store before 10 lines 
       after_buf = [] # buffer to store after 10 lines 
       corpusfile, corpusfile_clone = itertools.tee(corpusfile) # clone file iterator to access next 10 lines 
       for line in corpusfile: 
        line = line.strip() 
        if re.match('[A-Z]|[a-z]', line): 
         parts = line.split() 
         lemma = parts[2] 

         # before buffer handling, fill buffer excluded line contains any of excluded words 
         if not any(w in line for w in excluded_words): 
          before_buf.append(line) # append to before buffer 
         if len(before_buf)>11: 
          before_buf.pop(0) # keep the buffer at size 10 
         # next buffer handling 
         while len(after_buf)<=10: 
          try: 
           after = next(corpusfile_clone) # advance 1 iterator 
           after_lemma = '' 
           after_tmp = after.split() 
           if re.match('[A-Z]|[a-z]', after) and len(after_tmp)>2: 
            after_lemma = after_tmp[2] 
          except StopIteration: 
           break # copy iterator will exhaust 1st coz its 10 iteration ahead 
          if after_lemma and not any(w in after for w in excluded_words): 
           after_buf.append(after) # append to buffer 
           # print 'after',z,after, ' - ',after_lemma 
         if (after_buf and line in after_buf[0]): 
          after_buf.pop(0) # pop off one ready for next 

         if lemma in targets: 
          pos = parts[1] 
          if pos not in targets[lemma]: 
           targets[lemma][pos] = {} 
          counts = targets[lemma][pos] 
          # context = [] 
          # look at 10 previous lines 
          context= before_buf[:-1] # minus out current line 
          # look at the next 10 lines 
          context.extend(after_buf) 

          # END OF CHANGED CODE 
          # CONTINUE YOUR STUFF HERE WITH CONTEXT 
+0

Vay, iyi fikir! Yardımlarınız ve kodunuz için çok teşekkür ederim. Daha sonra bugün deneyeceğim ve hemen geri bildirim vereceğim. –

+0

Teşekkürler, bu çok yardımcı oluyor. Kaynak dosyada (corpusfile), arabelleğe okumadan önce dışlanması gereken satırlar da ('&', '\' veya '(bilinmeyen)', satırları içeren satırlar) dikkate almadım. Bunu bütün gün kodunuza eklemeyi denedim ama hiçbir yere gitmedim. Bir öneriniz var mı? Kesinlikle cowfile satırında olmalı: line = line.strip() _. Ancak bütün tamponlar berbat olur. –

+0

Orijinal kodunuzun açıkladığınız şeyi yapmadığı anlaşılıyor, sadece önceki ve 10 satırdan sonra olsun, ne olursa olsun yalnızca bağlamı işlerken kontrol edin; 2 satırdan önce 10 satırın dışında bilinmeyen gibi geçersiz sözcük içeriyorsa, o zaman sadece 8 satırdan ayrılırsınız. İstediğiniz şey filtreli olmalı ve tampondan önce ve sonra tüm 10 satırın filtre sözcükleri olmadan geçerli olduğundan emin olmalıyım, değil mi? Bunun için daha sonra kodumu düzenlemeyi deneyeceğim. – Skycc

1

Python 3.5 ile yazılmış bir işlevsel alternatif ilgilenir. Örneğinizi her iki tarafta sadece 5 kelime almak için basitleştirdim.Önemsiz değer filtrelemeyle ilgili başka basitleştirmeler vardır, ancak yalnızca küçük değişiklikler gerektirir. Bu işlevsel kodu okumak için daha doğal hale getirmek için PyPI'den fn paketini kullanacağım.

def getcol3(line: str) -> str: 
    return line.split("\t")[2] 

Sonra bir dayanak tarafından ayrılmış bloklara hatları bölmek için gereken:

from typing import List, Tuple 
from itertools import groupby, filterfalse 
from fn import F 

İlk sütun çıkarmak gerekir

TARGET_WORDS = {"target1", "target2"} 

# this is out predicate 
def istarget(word: str) -> bool: 
    return word in TARGET_WORDS   

filtre önemsiz sağlar ve bir işlev yazmak Son ve ilk 5 kelimeyi almak için:

def isjunk(word: str) -> bool: 
    return word == "(unknown)" 

def first_and_last(words: List[str]) -> (List[str], List[str]): 
    first = words[:5] 
    last = words[-5:] 
    return first, last 

Şimdi, gruplar dönelim:

Şimdi
words = (F() >> (map, str.strip) >> (filter, bool) >> (map, getcol3) >> (filterfalse, isjunk))(lines) 
groups = groupby(words, istarget) 

, süreç grupları

def is_target_group(group: Tuple[str, List[str]]) -> bool: 
    return istarget(group[0]) 

def unpack_word_group(group: Tuple[str, List[str]]) -> List[str]: 
    return [*group[1]] 

def unpack_target_group(group: Tuple[str, List[str]]) -> List[str]: 
    return [group[0]] 

def process_group(group: Tuple[str, List[str]]): 
    return (unpack_target_group(group) if is_target_group(group) 
      else first_and_last(unpack_word_group(group))) 

Ve son adımlar şunlardır:

words = list(map(process_group, groups)) 

Not; Bu çıktıyı alacak bu dosyayı Verilen

from io import StringIO 

buffer = """ 
_\t_\tword 
_\t_\tword 
_\t_\tword 
_\t_\t(unknown) 
_\t_\tword 
_\t_\tword 
_\t_\ttarget1 
_\t_\tword 
_\t_\t(unknown) 
_\t_\tword 
_\t_\tword 
_\t_\tword 
_\t_\ttarget2 
_\t_\tword 
_\t_\t(unknown) 
_\t_\tword 
_\t_\tword 
_\t_\tword 
_\t_\t(unknown) 
_\t_\tword 
_\t_\tword 
_\t_\ttarget1 
_\t_\tword 
_\t_\t(unknown) 
_\t_\tword 
_\t_\tword 
_\t_\tword 
""" 

# this simulates an opened file 
lines = StringIO(buffer) 

: Buradan

[(['word', 'word', 'word', 'word', 'word'], 
    ['word', 'word', 'word', 'word', 'word']), 
(['target1'], ['target1']), 
(['word', 'word', 'word', 'word'], ['word', 'word', 'word', 'word']), 
(['target2'], ['target2']), 
(['word', 'word', 'word', 'word', 'word'], 
    ['word', 'word', 'word', 'word', 'word']), 
(['target1'], ['target1']), 
(['word', 'word', 'word', 'word'], ['word', 'word', 'word', 'word'])] 

ilk 5 kelime ve son 5 kelime bırakabilirsiniz

Bu

benim test-durumdur.