Nhận biết một ngữ pháp trong một chuỗi các mã thông báo mờ


13

Tôi có tài liệu văn bản chứa chủ yếu danh sách các mục.

Mỗi Mục là một nhóm gồm nhiều mã thông báo từ các loại khác nhau: FirstName, LastName, BirthDate, PhoneNumber, City, Nghề nghiệp, v.v ... Mã thông báo là một nhóm từ.

Các mặt hàng có thể nằm trên một số dòng.

Các mục từ một tài liệu có cùng một cú pháp mã thông báo, nhưng chúng không nhất thiết phải giống hệt nhau.

Chúng có thể là một số ít hơn / ít mã thông báo giữa các Mục, cũng như trong các Mục.

FirstName LastName BirthDate PhoneNumber
Occupation City
FirstName LastName BirthDate PhoneNumber PhoneNumber
Occupation City
FirstName LastName BirthDate PhoneNumber
Occupation UnrecognizedToken
FirstName LastName PhoneNumber
Occupation City
FirstName LastName BirthDate PhoneNumber
City Occupation

Mục tiêu là xác định ngữ pháp được sử dụng, vd

Occupation City

và cuối cùng xác định tất cả các Mục, thậm chí nghĩ rằng chúng không khớp chính xác.

Để ngắn gọn và dễ đọc, thay vào đó hãy sử dụng một số bí danh A, B, C, D, ... để chỉ định các loại mã thông báo đó.

ví dụ

A B C
D F
A B C
D E F
F
A B C
D E E F
A C B
D E F
A B D C
D E F
A B C
D E F G

Ở đây chúng ta có thể thấy rằng cú pháp Item là

A B C
D E F

bởi vì nó là cái phù hợp nhất với chuỗi.

Cú pháp (loại mã thông báo và đơn đặt hàng) có thể thay đổi rất nhiều từ tài liệu này sang tài liệu khác. ví dụ: một tài liệu khác có thể có danh sách đó

D A
D A
D
D A
B
D A

Mục tiêu là tìm ra cú pháp mà không có kiến ​​thức trước về nó .

Từ bây giờ, một dòng mới cũng được coi là một mã thông báo. Sau đó, một tài liệu có thể được trình bày dưới dạng chuỗi mã thông báo 1 chiều:


Ở đây trình tự lặp lại sẽ là A B C Bvì nó là mã thông báo tạo ra ít xung đột nhất.

Hãy phức tạp hóa nó một chút. Từ bây giờ mỗi mã thông báo không có loại xác định. Trong thế giới thực, chúng tôi không phải lúc nào cũng chắc chắn 100% về một số loại mã thông báo. Thay vào đó, chúng tôi cung cấp cho nó một xác suất có một loại nhất định.

  A 0.2    A 0.0    A 0.1
  B 0.5    B 0.5    B 0.9     etc.
  C 0.0    C 0.0    C 0.0
  D 0.3    D 0.5    D 0.0

Đây là một hình ảnh trừu tượng về những gì tôi muốn đạt được:

Giải pháp được coi là A: Kết hợp một miếng token

Giải pháp này bao gồm việc áp dụng tích chập với một số bản vá mã thông báo và lấy mã tạo ra ít xung đột nhất.

Phần khó ở đây là tìm các bản vá tiềm năng để cuộn dọc theo chuỗi quan sát. Vài ý tưởng cho cái này, nhưng không có gì rất thỏa mãn:

Xây dựng mô hình Markov về quá trình chuyển đổi giữa các mã thông báo

Nhược điểm: vì một mô hình Markov không có bộ nhớ, chúng tôi sẽ mất các lệnh chuyển đổi. ví dụ: Nếu chuỗi lặp lại là A B C B D, chúng ta sẽ mất thực tế là A-> B xảy ra trước C-> B.

Xây dựng một cây hậu tố

Điều này dường như được sử dụng rộng rãi trong sinh học để phân tích nucleobase (GTAC) trong DNA / RNA. Nhược điểm: Cây Suffix rất phù hợp để kết hợp chính xác các mã thông báo chính xác (ví dụ: ký tự). Chúng tôi không có trình tự chính xác, cũng không có mã thông báo chính xác.

Lực lượng vũ phu

Hãy thử mọi sự kết hợp của mọi kích cỡ. Thực sự có thể làm việc, nhưng sẽ mất một thời gian (dài (dài)).

Giải pháp được coi là B: Xây dựng bảng khoảng cách Levenshtein của hậu tố

Trực giác là có thể tồn tại một số cực tiểu địa phương khi tính toán khoảng cách từ mọi hậu tố đến mọi hậu tố.

Hàm khoảng cách là khoảng cách Levenshtein, nhưng chúng ta sẽ có thể tùy chỉnh nó trong tương lai để tính đến xác suất của một loại nhất định, thay vì có một loại cố định cho mỗi mã thông báo.

Để đơn giản trong phần trình diễn đó, chúng tôi sẽ sử dụng mã thông báo loại cố định và sử dụng Levenshtein cổ điển để tính khoảng cách giữa các mã thông báo.

ví dụ: Hãy có chuỗi đầu vào ABCGDEFGH ABCDEFGH ABCDNEFGH.

Chúng tôi tính khoảng cách của mọi hậu tố với mọi hậu tố (được cắt thành kích thước bằng nhau):

for i = 0 to sequence.lengh
  for j = i to sequence.lengh
    # Create the suffixes
    suffixA = sequence.substr(i)
    suffixB = sequence.substr(j)
    # Make the suffixes the same size
    chunkLen = Math.min(suffixA.length, suffixB.length)
    suffixA = suffixA.substr(0, chunkLen)
    suffixB = suffixB.substr(0, chunkLen)
    # Compute the distance
    distance[i][j] = LevenshteinDistance(suffixA, suffixB)

Chúng tôi nhận được ví dụ như kết quả sau (màu trắng là khoảng cách nhỏ, màu đen là lớn):

Bây giờ, rõ ràng là bất kỳ hậu tố so với chính nó sẽ có một khoảng cách null. Nhưng chúng tôi không quan tâm bằng hậu tố (chính xác hoặc một phần) phù hợp với chính nó, vì vậy chúng tôi cắt phần đó.

Vì các hậu tố được cắt theo cùng kích thước, so sánh chuỗi dài sẽ luôn mang lại khoảng cách lớn hơn so với các chuỗi nhỏ hơn.

Chúng ta cần bù lại bằng một hình phạt mượt mà bắt đầu từ bên phải (+ P), mờ dần theo tuyến tính sang bên trái.

Tôi không chắc chắn làm thế nào để chọn một chức năng hình phạt tốt sẽ phù hợp với tất cả các trường hợp.

Ở đây chúng tôi áp dụng hình phạt (+ P = 6) ở cực bên phải, mờ dần về 0 sang trái.

Bây giờ chúng ta có thể thấy rõ 2 đường chéo rõ ràng xuất hiện. Có 3 Mục (Mục 1, Mục2, Mục 3) trong chuỗi đó. Dòng dài nhất đại diện cho sự phù hợp giữa Item1 vs Item2 và Item2 vs Item3. Dài thứ hai đại diện cho sự phù hợp giữa Item1 so với Item3.

Bây giờ tôi không chắc chắn về cách tốt nhất để khai thác dữ liệu đó. Có đơn giản như lấy các đường chéo cao nhất?

Hãy giả sử nó là.

Hãy tính giá trị trung bình của đường chéo bắt đầu từ mỗi mã thông báo. Chúng ta có thể thấy kết quả trên hình ảnh sau (vectơ bên dưới ma trận):

Rõ ràng có 3 cực tiểu địa phương, khớp với phần đầu của mỗi Mục. Trông tuyệt vời!

Bây giờ, hãy thêm một số khiếm khuyết nữa trong chuỗi: ABCGDEFGH ABCDEFGH TROLL ABCDEFGH

Rõ ràng bây giờ, vectơ trung bình đường chéo của chúng ta đã bị rối và chúng ta không thể khai thác nó nữa ...

Giả định của tôi là điều này có thể được giải quyết bằng một hàm khoảng cách tùy chỉnh (thay vì Levenshtein), trong đó việc chèn toàn bộ một khối có thể không bị phạt quá nhiều. Đó là những gì tôi không chắc chắn.

Phần kết luận

Không có giải pháp dựa trên tích chập nào được khám phá có vẻ phù hợp với vấn đề của chúng tôi.

Giải pháp dựa trên khoảng cách Levenshtein có vẻ đầy hứa hẹn, đặc biệt vì nó tương thích với các mã thông báo loại dựa trên xác suất. Nhưng tôi không chắc chắn về cách khai thác kết quả của nó.

Tôi sẽ rất biết ơn nếu bạn có kinh nghiệm trong một lĩnh vực liên quan và một vài gợi ý hay để cung cấp cho chúng tôi hoặc các kỹ thuật khác để khám phá. Cảm ơn bạn rất nhiều trước.


Bạn đã xem xét sử dụng một mô hình tự phát của một số loại? vi.wikipedia.org/wiki/AutoreTHERive_model
jcrudy

Tôi không thực sự hiểu những gì bạn muốn và tại sao. Nhưng có lẽ các thuật toán nén có thể giúp bằng cách nào đó.
Gerenuk

1
Tôi đã thêm một thử nghiệm tôi đã thực hiện ngày hôm nay, dựa trên khoảng cách levenshtein. Có vẻ đầy hứa hẹn. Ngoài ra, tôi đã chỉnh sửa một chút phần giới thiệu để hy vọng rõ ràng hơn. Cảm ơn bạn đã góp ý, tôi sẽ có một cái nhìn.
OoDeLally

@Gerenuk Thật là một nhận xét tuyệt vời!
uhbif19

Câu trả lời:


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.