2017-11-03 21 views
5

Tôi đã phát triển một mã chịu trách nhiệm đọc các từ của tệp txt, trong trường hợp "elquijote.txt" của tôi sau đó sử dụng từ điển {key: value} để hiển thị các từ xuất hiện và sự xuất hiện của chúng.Đọc các từ từ tệp txt - Python

Ví dụ cho một tập tin "test1.txt" với những lời sau đây:

hello hello hello good bye bye 

Kết quả của chương trình của tôi là:

hello 3 
good 1 
bye 2 

Một trong những lựa chọn mà chương trình đã, đang nó cho thấy những từ xuất hiện số lần lớn hơn số được giới thiệu bởi chúng tôi thông qua một đối số.

Nếu trong trình bao, chúng tôi đặt lệnh sau "python readingwords.py text.txt 2", sẽ hiển thị những từ chứa trong tệp "test1.txt" xuất hiện nhiều hơn số mà chúng tôi đã nhập trong trường hợp này 2

Output:

hello 3 

Bây giờ chúng ta có thể giới thiệu một số thứ ba của từ thông dụng như yếu tố quyết định liên từ, trong đó, là rất chung chung, chúng tôi không muốn được hiển thị hoặc giới thiệu trong của chúng tôi từ điển.

Mã của tôi hoạt động chính xác, vấn đề là sử dụng các tệp lớn, chẳng hạn như "elquijote.txt" mất nhiều thời gian để hoàn tất quá trình.

Tôi đã suy nghĩ và đó là vì việc tôi sử dụng danh sách phụ trợ của mình để loại bỏ các từ.

Tôi đã nghĩ là giải pháp không được giới thiệu trong danh sách của tôi những từ xuất hiện trong tệp txt được nhập bởi đối số, chứa các từ cần loại bỏ.

Đây là mã của tôi:

def contar(aux): 
    counts = {} 
    for palabra in aux: 
    palabra = palabra.lower() 
    if palabra not in counts: 
     counts[palabra] = 0 
    counts[palabra] += 1 
    return counts 

def main(): 

    characters = '!?¿-.:;-,><=*»¡' 
    aux = [] 
    counts = {} 

    with open(sys.argv[1],'r') as f: 
    aux = ''.join(c for c in f.read() if c not in characters) 
    aux = aux.split() 

    if (len(sys.argv)>3): 
    with open(sys.argv[3], 'r') as f: 
     remove = "".join(c for c in f.read()) 
     remove = remove.split() 

    #Borrar del archivo 
    for word in aux: 
     if word in remove: 
     aux.remove(word) 

    counts = contar(aux) 

    for word, count in counts.items(): 
    if count > int(sys.argv[2]): 
     print word, count 

if __name__ == '__main__': 
    main() 

Contar chức năng giới thiệu các từ trong từ điển.

Và chức năng chính giới thiệu trong danh sách "aux" những từ không chứa ký tự tượng trưng và sau đó xóa khỏi cùng danh sách những từ "cấm" được tải từ tệp .txt khác.

Tôi nghĩ giải pháp đúng là loại bỏ các từ bị cấm mà tôi loại bỏ các biểu tượng không được chấp nhận, nhưng sau khi thử một số cách tôi đã không quản lý để làm điều đó một cách chính xác.

Ở đây bạn có thể kiểm tra mã của mình trực tuyến: https://repl.it/Nf3S/54 Cảm ơn.

+0

tại sao không làm một từ bình thường đếm có thể với ** collections.Counter ** và sau đó loại bỏ từ không mong muốn của bạn sau khi? di chuyển mã chậm đến một vòng lặp âm lượng nhỏ hơn. –

+0

Bạn có gặp vấn đề gì về bộ nhớ không? "elquijote.txt" có thể là một tệp thực sự dài. Nếu nó là cuốn sách đầy đủ nó có 381.104 từ từ một tập hợp của 22.939 từ khác nhau và hơn 2 triệu ký tự. Việc xử lý hàng loạt cuốn sách phải là một ý tưởng hay. – Adirio

Trả lời

1

Có một vài sự không hiệu quả ở đây. Tôi đã viết lại mã của bạn để tận dụng lợi thế của một số tối ưu hóa này. Lý do cho mỗi thay đổi là trong các ý kiến ​​/ các chuỗi doc:

# -*- coding: utf-8 -*- 
import sys 
from collections import Counter 


def contar(aux): 
    """Here I replaced your hand made solution with the 
    built-in Counter which is quite a bit faster. 
    There's no real reason to keep this function, I left it to keep your code 
    interface intact. 
    """ 
    return Counter(aux) 

def replace_special_chars(string, chars, replace_char=" "): 
    """Replaces a set of characters by another character, a space by default 
    """ 
    for c in chars: 
     string = string.replace(c, replace_char) 
    return string 

def main(): 
    characters = '!?¿-.:;-,><=*»¡' 
    aux = [] 
    counts = {} 

    with open(sys.argv[1], "r") as f: 
     # You were calling lower() once for every `word`. Now we only 
     # call it once for the whole file: 
     contents = f.read().strip().lower() 
     contents = replace_special_chars(contents, characters) 
     aux = contents.split() 

    #Borrar del archivo 
    if len(sys.argv) > 3: 
     with open(sys.argv[3], "r") as f: 
      # what you had here was very ineffecient: 
      # remove = "".join(c for c in f.read()) 
      # that would create an array or characters then join them together as a string. 
      # this is a bit silly because it's identical to f.read(): 
      # "".join(c for c in f.read()) === f.read() 
      ignore_words = set(f.read().strip().split()) 
      """ignore_words is a `set` to allow for very fast inclusion/exclusion checks""" 
      aux = (word for word in aux if word not in ignore_words) 

    counts = contar(aux) 

    for word, count in counts.items(): 
     if count > int(sys.argv[2]): 
      print word, count 


if __name__ == '__main__': 
    main() 
+1

Có vẻ như chúng tôi đã có những ý tưởng rất giống nhau, nhưng bạn đánh tôi với cú đấm. –

+0

Thật vậy, nhưng tôi rất vui vì bạn đã vô tình giới thiệu tôi với một phương pháp mới: 'translate()'. Tôi không chắc chắn tôi sẽ sử dụng nó ở đây (tùy thuộc vào dữ liệu: dấu chấm câu sai/thiếu khoảng cách xung quanh dấu câu sẽ phá vỡ nó) nhưng tôi chắc chắn có thể tìm thấy nơi cho nó. Chúc mừng! – smassey

+1

Tôi đã sử dụng 'dịch' khá ngây thơ trong ví dụ của mình để đơn giản, nhưng bạn có thể tạo bảng dịch hoán đổi các ký tự được liệt kê cho một không gian thay vì xóa chúng, nếu đó là chức năng mong muốn. –

2

Dưới đây là một vài optimisations:

  • Sử dụng các bộ sưu tập.Số lượt truy cập() để đếm các mục trong contar()
  • Sử dụng string.translate() để xóa các ký tự không mong muốn
  • Các mục Pop từ danh sách từ bỏ qua sau khi đếm, thay vì tước chúng khỏi văn bản gốc.

Tốc độ tăng lên một chút, nhưng không phải theo thứ tự độ lớn.

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
import sys 
import os 
import collections 

def contar(aux): 
    return collections.Counter(aux) 

def main(): 

    characters = '!?¿-.:;-,><=*»¡' 
    aux = [] 
    counts = {} 

    with open(sys.argv[1],'r') as f: 
    text = f.read().lower().translate(None, characters) 
    aux = text.split() 

    if (len(sys.argv)>3): 
    with open(sys.argv[3], 'r') as f: 
     remove = set(f.read().strip().split()) 
    else: 
    remove = [] 

    counts = contar(aux) 
    for r in remove: 
    counts.pop(r, None) 

    for word, count in counts.items(): 
    if count > int(sys.argv[2]): 
     print word, count 

if __name__ == '__main__': 
    main() 
1

Một vài thay đổi và lý luận:

  1. lệnh Parse đối số dòng dưới __name__ == 'main': Bằng cách này, bạn thực thi mô đun mã của bạn bởi vì nó chỉ yêu cầu đối số dòng lệnh khi bạn chạy script này chính nó trái ngược với việc nhập hàm từ tập lệnh khác.
  2. Sử dụng regex để lọc các từ có ký tự bạn không muốn: Sử dụng regex cho phép bạn nói ký tự nào bạn muốn hoặc ký tự nào bạn KHÔNG muốn, tùy theo thời gian nào ngắn hơn. Trong trường hợp này, mã hóa mọi ký tự đặc biệt mà bạn không muốn là một công việc khá tẻ nhạt so với việc khai báo những ký tự nào bạn muốn trong một mẫu regex đơn giản. Trong tập lệnh sau, tôi lọc ra các từ không phải là chữ và số bằng cách sử dụng mẫu [aA-zZ0-9]+.
  3. Yêu cầu sự tha thứ trước khi cho phép: Vì đối số dòng lệnh đếm tối thiểu là tùy chọn nên rõ ràng là không phải lúc nào cũng có mặt. Do đó, chúng tôi có thể sử dụng các khối tryexcept để cố gắng xác định số lượng tối thiểu là sys.argv[2] và bắt ngoại lệ là IndexError để mặc định số lượng tối thiểu là 0.

Python script:

# sys 
import sys 
# regex 
import re 

def main(text_file, min_count): 
    word_count = {} 

    with open(text_file, 'r') as words: 
     # Clean words of linebreaks and split 
     # by ' ' to get list of words 
     words = words.read().strip().split(' ') 

     # Filter words that are not alphanum 
     pattern = re.compile(r'^[aA-zZ0-9]+$') 
     words = filter(pattern.search,words) 

     # Iterate through words and collect 
     # count 
     for word in words: 
      if word in word_count: 
       word_count[word] = word_count[word] + 1 
      else: 
       word_count[word] = 1 

    # Iterate for output 
    for word, count in word_count.items(): 
     if count > min_count: 
      print('%s %s' % (word, count)) 

if __name__ == '__main__': 
    # Get text file name 
    text_file = sys.argv[1] 

    # Attempt to get minimum count 
    # from command line. 
    # Default to 0 
    try: 
     min_count = int(sys.argv[2]) 
    except IndexError: 
     min_count = 0 

    main(text_file, min_count) 

Tiêu file:

hello hello hello good bye goodbye !bye bye¶ b?e goodbye 

Command:

python script.py text.txt 

Output:

bye 1 
good 1 
hello 3 
goodbye 2 

Với lệnh đếm tối thiểu:

python script.py text.txt 2 

Output:

hello 3 
Các vấn đề liên quan