ขั้นตอนที่ 3: เตรียมข้อมูล

ก่อนที่จะเปลี่ยนรูปแบบข้อมูลไปยังรูปแบบได้ จะต้องเปลี่ยนรูปแบบเป็นรูปแบบที่โมเดลเข้าใจได้

ประการแรก ตัวอย่างข้อมูลที่เรารวบรวมอาจเป็นลําดับที่เฉพาะเจาะจง เราไม่ต้องการให้ข้อมูลที่เกี่ยวข้องกับการจัดลําดับตัวอย่างมีผลต่อความสัมพันธ์ระหว่างข้อความและป้ายกํากับ เช่น หากมีการจัดเรียงชุดข้อมูลตามชั้นเรียน แล้วแยกเป็นชุดการฝึก/การตรวจสอบ ชุดเหล่านี้จะไม่แสดงถึงการกระจายข้อมูลโดยรวม

แนวทางปฏิบัติแนะนําง่ายๆ เพื่อให้แน่ใจว่าโมเดลจะไม่ได้รับผลกระทบจากลําดับข้อมูลคือสับเปลี่ยนข้อมูลเสมอก่อนที่จะดําเนินการใดๆ หากมีการแยกข้อมูลออกเป็นชุดการฝึกและการตรวจสอบอยู่แล้ว ให้เปลี่ยนข้อมูลการตรวจสอบด้วยวิธีเดียวกับการเปลี่ยนข้อมูลการฝึก หากยังไม่มีชุดการฝึกและการตรวจสอบแยกกัน คุณสามารถแยกตัวอย่างหลังการสุ่มได้ โดยทั่วไปแล้วจะใช้ตัวอย่าง 80% สําหรับการฝึกอบรมและ 20% สําหรับการตรวจสอบ

ประการที่ 2 อัลกอริทึมแมชชีนเลิร์นนิงใช้ตัวเลขเป็นอินพุต ซึ่งหมายความว่า เราจะต้องแปลงข้อความเป็นเวกเตอร์ตัวเลข กระบวนการนี้มี 2 ขั้นตอน ดังนี้

  1. การนําโทเค็นไปใช้: แบ่งข้อความออกเป็นคําหรือข้อความย่อยขนาดเล็ก ซึ่งจะทําให้มีความสัมพันธ์ที่ดีระหว่างความสัมพันธ์ระหว่างข้อความและป้ายกํากับได้ คอลัมน์นี้จะเป็นตัวกําหนด "คําศัพท์" ของชุดข้อมูล (ชุดโทเค็นที่ไม่ซ้ํากันซึ่งมีอยู่ในข้อมูล)

  2. การกําหนดเวกเตอร์: กําหนดการวัดตัวเลขที่ดีเพื่อระบุลักษณะของข้อความเหล่านี้

ดูวิธีดําเนินการ 2 ขั้นตอนนี้สําหรับทั้งเวกเตอร์และเวกเตอร์ลําดับ รวมถึงวิธีเพิ่มประสิทธิภาพการแสดงเวกเตอร์โดยใช้เทคนิคการเลือกฟีเจอร์และการปรับให้เป็นมาตรฐาน

เวกเตอร์ N-gram [ตัวเลือก A]

ในย่อหน้าถัดไป เราจะดูวิธีการกําหนดโทเค็นและทําให้เวกเตอร์สําหรับโมเดล N-gram นอกจากนี้เราจะพูดถึงวิธีที่เราเพิ่มประสิทธิภาพการนําเสนอ N-gram โดยใช้เทคนิคการเลือกคุณลักษณะและการปรับให้สอดคล้องตามมาตรฐาน

ในเวกเตอร์ N-gram ข้อความจะแสดงเป็นคอลเล็กชันของ N-Ggrams ที่ไม่ซ้ํากัน นั่นคือ กลุ่มของโทเค็น N ซึ่งอยู่ติดกัน (โดยทั่วไปจะเป็นคํา) พิจารณาข้อความ The mouse ran up the clock ในตัวอย่างนี้ คําว่า unigrams (n = 1) คือ ['the', 'mouse', 'ran', 'up', 'clock'], คําว่า bigrams (n = 2) มีค่าเป็น ['the mouse', 'mouse ran', 'ran up', 'up the', 'the clock'] เป็นต้น

การทําโทเค็น

เราพบว่าการใช้โทเค็นที่มีสูตรพิเศษ + สูตรบิ๊กซี ทําให้ได้ความแม่นยําที่ดี ทั้งยังใช้เวลาในการประมวลผลน้อยลง

เวกเตอร์

เมื่อเราแยกตัวอย่างข้อความเป็น n-ggram แล้ว เราต้องเปลี่ยน n-gram เหล่านี้เป็นเวกเตอร์ตัวเลขที่โมเดลแมชชีนเลิร์นนิงของเราประมวลผลได้ ตัวอย่างด้านล่างแสดงดัชนีที่กําหนดให้กับ Unigrams และ Bigram ที่สร้างขึ้นสําหรับสองข้อความ

Texts: 'The mouse ran up the clock' and 'The mouse ran down'
Index assigned for every token: {'the': 7, 'mouse': 2, 'ran': 4, 'up': 10,
  'clock': 0, 'the mouse': 9, 'mouse ran': 3, 'ran up': 6, 'up the': 11, 'the
clock': 8, 'down': 1, 'ran down': 5}

เมื่อกําหนดดัชนีไปยัง n-grams แล้ว โดยปกติเราจะแปลงข้อมูลเป็นเวกเตอร์โดยใช้หนึ่งในตัวเลือกต่อไปนี้

การเข้ารหัสแบบใช้ครั้งเดียว: ข้อความตัวอย่างทุกข้อความจะแสดงเป็นเวกเตอร์ที่บ่งบอกว่ามีหรือไม่มีโทเค็นอยู่ในข้อความ

'The mouse ran up the clock' = [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1]

การเข้ารหัสการนับ: ตัวอย่างข้อความทุกข้อความจะแสดงเป็นเวกเตอร์ซึ่งระบุจํานวนโทเค็นในข้อความ โปรดทราบว่าตอนนี้องค์ประกอบที่เกี่ยวข้องกับ Unigram '' (ตัวหนาด้านล่าง) จะแสดงเป็น 2 เนื่องจากคําว่า "the" ปรากฏขึ้น 2 ครั้งในข้อความ

'The mouse ran up the clock' = [1, 0, 1, 1, 1, 0, 1, 2, 1, 1, 1, 1]

การเข้ารหัส ff-idf: ปัญหา 2 ประการข้างต้นคือ คําทั่วไปที่เกิดขึ้นบ่อยด้วยเอกสารทั้งหมด (กล่าวคือ คําที่ไม่เฉพาะเจาะจงเป็นพิเศษสําหรับตัวอย่างข้อความในชุดข้อมูล) จะไม่ถูกลงโทษ เช่น คําอย่าง "ก" จะเกิดขึ้นบ่อยมากในทุกข้อความ จํานวนโทเค็นของ "the" ที่สูงกว่าคําอื่นๆ ที่มีความหมายไม่เป็นประโยชน์มากนัก

'The mouse ran up the clock' = [0.33, 0, 0.23, 0.23, 0.23, 0, 0.33, 0.47, 0.33,
0.23, 0.33, 0.33] (See Scikit-learn TfidfTransformer)

มีการนําเสนอเวกเตอร์อื่นๆ อยู่มากมาย แต่สามรูปแบบข้างต้นมีการใช้งานบ่อยที่สุด

เราสังเกตเห็นว่าการเข้ารหัส tf-idf ดีกว่าอีก 2 ส่วนอย่างมากในแง่ความถูกต้อง (โดยเฉลี่ย 0.25-15%) และขอแนะนําให้ใช้วิธีนี้ในการนับเวกเตอร์ n-grams แต่อย่าลืมว่าจะใช้หน่วยความจํามากขึ้น (เนื่องจากใช้การนําเสนอในจุดแบบลอย) และใช้เวลาในการประมวลผลมากขึ้น โดยเฉพาะอย่างยิ่งสําหรับชุดข้อมูลขนาดใหญ่ (อาจใช้เวลานานกว่า 2 ครั้งในบางกรณี)

การเลือกฟีเจอร์

เมื่อเราแปลงข้อความทั้งหมดในชุดข้อมูลเป็นโทเค็น uni+bigram เราก็อาจใช้โทเค็นหลายหมื่นรูปแบบ โทเค็น/ฟีเจอร์เหล่านี้บางรายการไม่ได้ ส่งผลต่อการคาดคะเนป้ายกํากับ เราสามารถตัดโทเค็นบางรายการออกไปได้ เช่น โทเค็นที่เกิดขึ้นน้อยมากในชุดข้อมูล นอกจากนี้ เรายังวัดความสําคัญของฟีเจอร์ได้ (โทเค็นแต่ละรายการมีส่วนช่วยสร้างการคาดการณ์ป้ายกํากับมากน้อยเพียงใด) และรวมเฉพาะโทเค็นที่ให้ข้อมูลมากที่สุดเท่านั้น

มีฟังก์ชันทางสถิติมากมายที่ใช้ฟีเจอร์ต่างๆ และป้ายกํากับที่เกี่ยวข้อง และแสดงผลลัพธ์ความสําคัญของคะแนนฟีเจอร์ ฟังก์ชันที่ใช้กันโดยทั่วไปคือ f_classif และ chi2 การทดสอบของเราแสดงให้เห็นว่าฟังก์ชันทั้งสองนี้มีประสิทธิภาพเท่ากัน

ยิ่งไปกว่านั้น เราพบว่าความแม่นยําสูง โดยมีฟีเจอร์ประมาณ 20,000 รายการสําหรับชุดข้อมูลหลายชุด (ดูรูปที่ 6) การใส่ฟีเจอร์มากกว่าเกณฑ์นี้จะส่งผลเพียงเล็กน้อยและบางครั้งก็ทําให้เพิ่มประสิทธิภาพ และเสื่อมประสิทธิภาพได้

K เทียบกับความถูกต้อง

รูปที่ 6: ฟีเจอร์ K สูงสุดเทียบกับความถูกต้อง ที่ราบสูงมีความแม่นยําสูงเกี่ยวกับฟีเจอร์ประมาณ 20, 000 อันดับแรกในทุกชุดข้อมูล

การปรับให้เป็นมาตรฐาน

การปรับค่าให้เป็นมาตรฐานจะแปลงการแปลงฟีเจอร์/ตัวอย่างทั้งหมดเป็นค่าที่เล็กและคล้ายกัน ซึ่งจะช่วยให้การบรรจบกันของการไล่ระดับสีในอัลกอริทึมการเรียนรู้ทําได้ง่ายขึ้น จากข้อมูลที่ได้เห็น การปรับการประมวลผลข้อมูลให้เป็นมาตรฐานโดยอัตโนมัติดูเหมือนจะเพิ่มคุณค่าให้กับปัญหาการจัดประเภทข้อความอย่างมาก เราขอแนะนําให้คุณข้ามขั้นตอนนี้

โค้ดต่อไปนี้จะรวมขั้นตอนทั้งหมดข้างต้นเข้าด้วยกัน

  • แปลงตัวอย่างข้อความให้เป็น uni+bigram ของคํา
  • เวกเตอร์โดยใช้การเข้ารหัส tf-idf
  • เลือกเฉพาะฟีเจอร์ 20,000 รายการแรกจากเวกเตอร์ของโทเค็นโดยทิ้งโทเค็นที่ปรากฏน้อยกว่า 2 ครั้ง แล้วใช้ f_classif ในการคํานวณความสําคัญของฟีเจอร์
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif

# Vectorization parameters
# Range (inclusive) of n-gram sizes for tokenizing text.
NGRAM_RANGE = (1, 2)

# Limit on the number of features. We use the top 20K features.
TOP_K = 20000

# Whether text should be split into word or character n-grams.
# One of 'word', 'char'.
TOKEN_MODE = 'word'

# Minimum document/corpus frequency below which a token will be discarded.
MIN_DOCUMENT_FREQUENCY = 2

def ngram_vectorize(train_texts, train_labels, val_texts):
    """Vectorizes texts as n-gram vectors.

    1 text = 1 tf-idf vector the length of vocabulary of unigrams + bigrams.

    # Arguments
        train_texts: list, training text strings.
        train_labels: np.ndarray, training labels.
        val_texts: list, validation text strings.

    # Returns
        x_train, x_val: vectorized training and validation texts
    """
    # Create keyword arguments to pass to the 'tf-idf' vectorizer.
    kwargs = {
            'ngram_range': NGRAM_RANGE,  # Use 1-grams + 2-grams.
            'dtype': 'int32',
            'strip_accents': 'unicode',
            'decode_error': 'replace',
            'analyzer': TOKEN_MODE,  # Split text into word tokens.
            'min_df': MIN_DOCUMENT_FREQUENCY,
    }
    vectorizer = TfidfVectorizer(**kwargs)

    # Learn vocabulary from training texts and vectorize training texts.
    x_train = vectorizer.fit_transform(train_texts)

    # Vectorize validation texts.
    x_val = vectorizer.transform(val_texts)

    # Select top 'k' of the vectorized features.
    selector = SelectKBest(f_classif, k=min(TOP_K, x_train.shape[1]))
    selector.fit(x_train, train_labels)
    x_train = selector.transform(x_train).astype('float32')
    x_val = selector.transform(x_val).astype('float32')
    return x_train, x_val

สําหรับการแสดงแทนเวกเตอร์ N-gram เราทิ้งข้อมูลจํานวนมากเกี่ยวกับการเรียงลําดับคํา และไวยากรณ์ (ที่ดีที่สุดคือ เราสามารถรักษาข้อมูลการจัดลําดับบางส่วน เมื่อ n > 1) ได้ เราเรียกแนวทางนี้ว่าแนวทางการแสดงออก การนําเสนอนี้ใช้ร่วมกับโมเดลที่ไม่ได้คํานึงถึงการจัดลําดับ เช่น การถดถอยแบบโลจิสติก การดาวน์โหลดแบบหลายชั้น เครื่องไล่ระดับสี การรองรับเครื่องเวกเตอร์

เวกเตอร์ลําดับ [ตัวเลือก B]

ในย่อหน้าถัดไป เราจะดูวิธีการกําหนดโทเค็นและทําให้เวกเตอร์สําหรับโมเดลลําดับ นอกจากนี้เราจะพูดถึงวิธีที่เราสามารถเพิ่มประสิทธิภาพการแสดงลําดับโดยใช้เทคนิคการเลือกและการปรับให้เป็นมาตรฐาน

สําหรับตัวอย่างข้อความบางรายการ ลําดับคํามีความสําคัญกับความหมายของข้อความ เช่น ประโยคที่ว่า "ผมเคยเกลียดการเดินทางของตัวเอง ฉันเข้าใจจักรยานแบบใหม่ของฉัน โดยสมบูรณ์" เมื่ออ่านตามลําดับเท่านั้น โมเดลอย่าง CNNs/RNNs อาจอนุมานความหมายจากลําดับของคําในตัวอย่างได้ สําหรับรูปแบบเหล่านี้ เราจะนําเสนอข้อความเป็นลําดับโทเค็น เก็บลําดับไว้

การทําโทเค็น

ข้อความอาจแสดงเป็นลําดับอักขระหรือลําดับของคํา เราพบว่าการใช้การแสดงระดับคําจะให้ประสิทธิภาพดีกว่าโทเค็นอักขระ กฎเกณฑ์เหล่านี้ก็ใช้ในทิศทางปกติของอุตสาหกรรมด้วยเช่นกัน การใช้โทเค็นอักขระถือว่าสมเหตุสมผลเฉพาะในกรณีที่ข้อความมีการพิมพ์ผิดบ่อยครั้ง ซึ่งปกติไม่เป็นเช่นนั้น

เวกเตอร์

เมื่อเราแปลงตัวอย่างข้อความเป็นลําดับคําแล้ว เราต้องเปลี่ยนลําดับเหล่านี้เป็นเวกเตอร์ตัวเลข ตัวอย่างด้านล่างแสดงดัชนีที่กําหนดให้กับ Unigram ที่สร้างขึ้นสําหรับข้อความสองข้อความ จากนั้นลําดับของดัชนีโทเค็นที่จะแปลงข้อความแรก

Texts: 'The mouse ran up the clock' and 'The mouse ran down'
Index assigned for every token: {'clock': 5, 'ran': 3, 'up': 4, 'down': 6, 'the': 1, 'mouse': 2}.
NOTE: 'the' occurs most frequently, so the index value of 1 is assigned to it.
Some libraries reserve index 0 for unknown tokens, as is the case here.
Sequence of token indexes: 'The mouse ran up the clock' = [1, 2, 3, 4, 1, 5]

มี 2 ตัวเลือกในการทําให้ลําดับโทเค็นเป็นสัญลักษณ์ของเวกเตอร์ได้ ดังนี้

การเข้ารหัสแบบใช้ครั้งเดียว: ลําดับจะแสดงโดยใช้เวกเตอร์คําในรูปขนาด n ตามขนาด n = ขนาดของคําศัพท์ การนําเสนอนี้ใช้ได้ผลดีเมื่อ เราใช้โทเค็นเป็นอักขระ ทําให้คําศัพท์นั้นมีน้อย เมื่อเราเปลี่ยนคําพูดเป็นคํา คําศัพท์มักจะมีโทเค็นเป็นหมื่นคํา ทําให้เวกเตอร์ที่ร้อนแรงน้อยมาก ตัวอย่าง

'The mouse ran up the clock' = [
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 1, 0, 0, 0, 0],
  [0, 0, 0, 1, 0, 0, 0],
  [0, 0, 0, 0, 1, 0, 0],
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 1, 0]
]

การฝังคํา: คําที่มีความหมายเชื่อมโยงอยู่ ผลที่ได้คือเราสามารถแสดงถึงโทเค็นคําในพื้นที่เวกเตอร์ที่หนาแน่น (จํานวนจริงประมาณ 200 หลัก) โดยที่ตําแหน่งและระยะทางระหว่างคําจะบ่งชี้ความคล้ายคลึงกันของความหมาย (ดูรูปที่ 7) การนําเสนอนี้เรียกว่าการฝังคํา

การฝังข้อความ

รูปที่ 7: การฝังคํา

โมเดลลําดับมักมีเลเยอร์แบบฝังเป็นเลเยอร์แรก ชั้นนี้จะเรียนรู้วิธีเปลี่ยนลําดับดัชนีคําเป็นเวกเตอร์การฝังคําในระหว่างกระบวนการฝึก เพื่อให้ดัชนีคําแต่ละรายการจับคู่กับเวกเตอร์ที่หนาแน่นของค่าจริงซึ่งแสดงถึงตําแหน่งของคํานั้นในความหมาย (ดูรูปที่ 8)

การฝังเลเยอร์

รูปที่ 8: การฝังเลเยอร์

การเลือกฟีเจอร์

คําทุกคําในข้อมูลของเรามีส่วนในการคาดการณ์ป้ายกํากับไม่ได้ เราสามารถเพิ่มประสิทธิภาพกระบวนการเรียนรู้ได้ด้วยการตัดคําที่พบไม่บ่อยหรือไม่เกี่ยวข้องออกจากคําศัพท์ของเรา อันที่จริงเราพบว่าการใช้ฟีเจอร์ที่พบได้บ่อยที่สุด 20,000 ครั้งนั้นเพียงพอแล้ว กรณีนี้เกิดขึ้นกับโมเดล n-gram ด้วยเช่นกัน (ดูรูปที่ 6)

เราจะรวมขั้นตอนทั้งหมดข้างต้นไว้ในการเรียงข้อมูลตามลําดับด้วยกัน โค้ดต่อไปนี้จะดําเนินการต่อไปนี้

  • แปลงข้อความเป็นคํา
  • สร้างคําศัพท์โดยใช้โทเค็น 20,000 อันดับแรก
  • แปลงโทเค็นให้เป็นเวกเตอร์ของลําดับ
  • เลื่อนลําดับที่มีความยาวคงที่
from tensorflow.python.keras.preprocessing import sequence
from tensorflow.python.keras.preprocessing import text

# Vectorization parameters
# Limit on the number of features. We use the top 20K features.
TOP_K = 20000

# Limit on the length of text sequences. Sequences longer than this
# will be truncated.
MAX_SEQUENCE_LENGTH = 500

def sequence_vectorize(train_texts, val_texts):
    """Vectorizes texts as sequence vectors.

    1 text = 1 sequence vector with fixed length.

    # Arguments
        train_texts: list, training text strings.
        val_texts: list, validation text strings.

    # Returns
        x_train, x_val, word_index: vectorized training and validation
            texts and word index dictionary.
    """
    # Create vocabulary with training texts.
    tokenizer = text.Tokenizer(num_words=TOP_K)
    tokenizer.fit_on_texts(train_texts)

    # Vectorize training and validation texts.
    x_train = tokenizer.texts_to_sequences(train_texts)
    x_val = tokenizer.texts_to_sequences(val_texts)

    # Get max sequence length.
    max_length = len(max(x_train, key=len))
    if max_length > MAX_SEQUENCE_LENGTH:
        max_length = MAX_SEQUENCE_LENGTH

    # Fix sequence length to max value. Sequences shorter than the length are
    # padded in the beginning and sequences longer are truncated
    # at the beginning.
    x_train = sequence.pad_sequences(x_train, maxlen=max_length)
    x_val = sequence.pad_sequences(x_val, maxlen=max_length)
    return x_train, x_val, tokenizer.word_index

เวกเตอร์ป้ายกํากับ

เราได้พบกับการแปลงข้อมูลข้อความตัวอย่างเป็นเวกเตอร์ตัวเลข กระบวนการที่คล้ายกัน ต้องใช้กับป้ายกํากับ เราสามารถแปลงป้ายกํากับเป็นค่าที่อยู่ในช่วง [0, num_classes - 1] ได้ เช่น หากมี 3 คลาส เราใช้ ค่า 0, 1 และ 2 เพื่อแทนค่าได้ ภายใน เครือข่ายจะใช้เวกเตอร์แบบใช้ครั้งเดียวเพื่อแสดงค่าเหล่านี้ (เพื่อหลีกเลี่ยงการสรุปความสัมพันธ์ที่ไม่ถูกต้องระหว่างป้ายกํากับ) การนําเสนอนี้ขึ้นอยู่กับฟังก์ชันการสูญเสียและฟังก์ชันการเปิดใช้งานเลเยอร์ล่าสุดที่เราใช้ในเครือข่ายระบบประสาท เราจะดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ ในส่วนถัดไป