2012-03-08 71 views
5

Tôi đang viết một tập lệnh ETL bằng Python nhận dữ liệu trong tệp CSV, xác thực và vệ sinh dữ liệu cũng như phân loại hoặc phân loại từng hàng theo một số quy tắc và cuối cùng tải nó vào một cơ sở dữ liệu postgresql.Cách phân loại/phân loại chuỗi theo quy tắc biểu thức chính quy trong Python

Dữ liệu trông như thế này (giản thể):

 
ColA, ColB, Timestamp, Timestamp, Journaltext, AmountA, AmountB 

Mỗi hàng là một giao dịch tài chính. Điều tôi muốn làm là phân loại hoặc phân loại các giao dịch dựa trên một số quy tắc. Các quy tắc về cơ bản là các biểu thức chính quy phù hợp với văn bản trong cột Journaltext.

Vì vậy, những gì tôi muốn làm là một cái gì đó như thế này:

 
transactions = [] 
for row in rows: 
    t = Transaction(category=classify(row.journaltext)) 
    transactions.append(t) 

Tôi không chắc chắn làm thế nào để viết classify() chức năng một cách hiệu quả.

Đây là cách các quy tắc để phân loại hoạt động:

  • Có một số chủng loại (hơn có thể và sẽ được bổ sung sau)
  • Mỗi thể loại có một tập hợp các chuỗi con hoặc biểu thức thông thường rằng, nếu Journaltext của một giao dịch khớp với biểu thức này hoặc chứa chuỗi con này, thì giao dịch này thuộc về thể loại này.
  • Giao dịch chỉ có thể ở trên một danh mục
  • Nếu danh mục, FOO, có foo 'và' Foo 'và một loại BAR khác có' bóng đá ', sau đó giao dịch với Journaltext =' food 'phải được đặt trong danh mục FOO, vì nó chỉ khớp với FOO, nhưng một giao dịch với Journaltext = 'footballs' phải được đặt trong danh mục BAR. Tôi nghĩ điều này có nghĩa là tôi phải đặt ưu tiên hoặc tương tự trên mỗi danh mục.
  • Nếu giao dịch không khớp với bất kỳ cụm từ nào, giao dịch sẽ không có trong danh mục hoặc sẽ được đặt trong danh mục trình giữ chỗ được gọi là "UNKNOWN" hoặc tương tự. Điều này không quan trọng lắm.

Ok. Vì vậy, làm thế nào để tôi đại diện cho các loại này và các quy tắc tương ứng trong Python?

Tôi thực sự đánh giá cao ý kiến ​​của bạn. Ngay cả khi bạn không thể cung cấp giải pháp đầy đủ. Chỉ cần bất cứ điều gì để gợi ý cho tôi đi đúng hướng sẽ là tuyệt vời. Cảm ơn.

+1

lớn như thế nào là đầu vào của bạn (số chủng loại, về mỗi loại, số lượng giao dịch và kích thước trung bình của văn bản)? –

Trả lời

2

Nếu không có bất kỳ loại của fluff thêm:

categories = [ 
    ('cat1', ['foo']), 
    ('cat2', ['football']), 
    ('cat3', ['abc', 'aba', 'bca']) 
] 

def classify(text): 
    for category, matches in categories: 
    if any(match in text for match in matches): 
     return category 
    return None 

Trong Python bạn có thể sử dụng toán tử in để kiểm tra các tập con của một chuỗi. Bạn có thể thêm một số thứ như isinstance(match, str) để kiểm tra xem bạn đang sử dụng một chuỗi đơn giản hay một đối tượng cụm từ thông dụng. Mức độ nâng cao của nó tùy thuộc vào bạn.

+0

Điều này có vẻ thanh lịch, tuy nhiên, nó dường như không hoạt động nếu các loại có nhiều hơn một chuỗi con. Làm thế nào để làm điều đó? Giả sử, cat3 có các bản chất: 'aba', 'abe' và 'bca' – ervingsb

+0

@ervingsb - Hãy xem các điều chỉnh đó - chúng cho phép nhiều kết quả phù hợp cho mỗi danh mục. Mức độ ưu tiên được xác định theo thứ tự bạn đặt mọi thứ vào danh sách 'danh mục' chính. –

+1

@ervingsb: Nếu bạn sử dụng các biểu thức chính quy, bạn cũng có thể điều chỉnh chúng để sử dụng luân phiên ('abc | abe | bca'), đơn giản hóa mã và * có thể * cho kết quả tốt hơn (tùy thuộc vào việc thực thi regex). –

2

gì về giải pháp này trong giả python:

def classify(journaltext): 
    prio_list = ["FOO", "BAR", "UPS", ...] # "..." is a placeholder: you have to give the full list here. 
    # dictionary: 
    # - key is the name of the category, must match the name in the above prio_list 
    # - value is the regex that identifies the category 
    matchers = {"FOO": "the regex for FOO", "BAR": "the regex for BAR", "UPS":"...", ...} 
    for category in prio_list: 
     if re.match(matchers[category], journaltext): 
      return category 
    return "UNKOWN" # or you can "return None" 

Các tính năng:

  • này có một prio_list, đó là tất cả các loại theo thứ tự giảm dần.
  • nó cố gắng khớp theo thứ tự của danh sách.
  • Kết quả trùng khớp với một regex từ đối sánh từ từ điển. Vì vậy, tên danh mục có thể tùy ý.
  • hàm trả về tên của danh mục
  • nếu không có gì phù hợp, khi đó bạn sẽ có được tên danh mục phần giữ chỗ của mình.

Bạn thậm chí có thể đọc danh sách hạng mục ưu tiên và regexs từ một tập tin cấu hình, nhưng điều này là trái như một bài tập cho người đọc ...

+0

Làm cách nào để hỗ trợ nhiều hơn một chuỗi/regex cho danh mục FOO? Tôi không thể đặt nhiều hơn một khóa 'foo' vào dict. – ervingsb

+0

bạn có thể đặt nhiều hơn một chuỗi con với nhau trong một regex đơn: "(foo | bar)" khớp với các chuỗi chứa "foo" hoặc "bar". Và regexes cann là trường hợp insensitiv, xem http://docs.python.org/howto/regex.html cho một python regex howto. –

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