8.2. Metin Ön İşleme¶ Open the notebook in SageMaker Studio Lab
Dizi verileri için istatistiksel araçları ve tahmin zorluklarını inceledik ve değerlendirdik. Bu veriler birçok şekil alabilir. Özellikle, kitabın birçok bölümünde odaklanacağımız gibi, metinler dizi verilerinin en popüler örneklerindendir. Örneğin, bir makale basitçe bir sözcük dizisi veya hatta bir karakter dizisi olarak görülebilir. Dizi verileriyle gelecekteki deneylerimizi kolaylaştırmak amacıyla, bu bölümü metin için ortak ön işleme adımlarını açıklamaya adayacağız. Genellikle, aşağıdaki adımlar vardır:
Metni dizgi (string) olarak belleğe yükleyin.
Dizgileri andıçlara (token) ayırın (örn. kelimeler ve karakterler).
Bölünmüş andıçları sayısal indekslerle eşlemek için bir kelime tablosu oluşturun.
Metni sayısal indekslerin dizilerine dönüştürün, böylece modeller tarafından kolayca işlenebilirler.
import collections
import re
from d2l import mxnet as d2l
import collections
import re
from d2l import torch as d2l
import collections
import re
from d2l import tensorflow as d2l
8.2.1. Veri Kümesini Okuma¶
Başlamak için H. G. Wells’in *Zaman Makinesi*’nden metin yüklüyoruz. Bu 30000 kelimenin biraz üzerinde oldukça küçük bir külliyat, ama göstermek istediğimiz şey için gayet iyi. Daha gerçekçi belge koleksiyonları milyarlarca kelime içerir. Aşağıdaki işlev, veri kümesini her satırın bir dizgi olduğu metin satırları listesine okur. Basitlik için, burada noktalama işaretlerini ve büyük harfleri görmezden geliyoruz.
#@save
d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt',
'090b5e7e70c295757f55df93cb0a180b9691891a')
def read_time_machine(): #@save
"""Zaman makinesi veri kümesini bir metin satırı listesine yükleyin."""
with open(d2l.download('time_machine'), 'r') as f:
lines = f.readlines()
return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]
lines = read_time_machine()
print(f'# text lines: {len(lines)}')
print(lines[0])
print(lines[10])
# text lines: 3221
the time machine by h g wells
twinkled and his usually pale face was flushed and animated the
#@save
d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt',
'090b5e7e70c295757f55df93cb0a180b9691891a')
def read_time_machine(): #@save
"""Zaman makinesi veri kümesini bir metin satırı listesine yükleyin."""
with open(d2l.download('time_machine'), 'r') as f:
lines = f.readlines()
return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]
lines = read_time_machine()
print(f'# text lines: {len(lines)}')
print(lines[0])
print(lines[10])
# text lines: 3221
the time machine by h g wells
twinkled and his usually pale face was flushed and animated the
#@save
d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt',
'090b5e7e70c295757f55df93cb0a180b9691891a')
def read_time_machine(): #@save
"""Zaman makinesi veri kümesini bir metin satırı listesine yükleyin."""
with open(d2l.download('time_machine'), 'r') as f:
lines = f.readlines()
return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]
lines = read_time_machine()
print(f'# text lines: {len(lines)}')
print(lines[0])
print(lines[10])
# text lines: 3221
the time machine by h g wells
twinkled and his usually pale face was flushed and animated the
8.2.2. Andıçlama¶
Aşağıdaki tokenize
işlevi, girdi olarak bir liste (lines
) alır
ve burada her eleman bir metin dizisidir (örneğin, bir metin satırı).
Her metin dizisi bir andıç listesine bölünür. Andıç metindeki temel
birimdir. Sonunda, her andıcın bir dizgi olduğu andıç listelerinin bir
listesi döndürülür.
def tokenize(lines, token='word'): #@save
"""Metin satırlarını kelime veya karakter belirteçlerine ayırın."""
if token == 'word':
return [line.split() for line in lines]
elif token == 'char':
return [list(line) for line in lines]
else:
print('ERROR: unknown token type: ' + token)
tokens = tokenize(lines)
for i in range(11):
print(tokens[i])
['the', 'time', 'machine', 'by', 'h', 'g', 'wells']
[]
[]
[]
[]
['i']
[]
[]
['the', 'time', 'traveller', 'for', 'so', 'it', 'will', 'be', 'convenient', 'to', 'speak', 'of', 'him']
['was', 'expounding', 'a', 'recondite', 'matter', 'to', 'us', 'his', 'grey', 'eyes', 'shone', 'and']
['twinkled', 'and', 'his', 'usually', 'pale', 'face', 'was', 'flushed', 'and', 'animated', 'the']
def tokenize(lines, token='word'): #@save
"""Metin satırlarını kelime veya karakter belirteçlerine ayırın."""
if token == 'word':
return [line.split() for line in lines]
elif token == 'char':
return [list(line) for line in lines]
else:
print('ERROR: unknown token type: ' + token)
tokens = tokenize(lines)
for i in range(11):
print(tokens[i])
['the', 'time', 'machine', 'by', 'h', 'g', 'wells']
[]
[]
[]
[]
['i']
[]
[]
['the', 'time', 'traveller', 'for', 'so', 'it', 'will', 'be', 'convenient', 'to', 'speak', 'of', 'him']
['was', 'expounding', 'a', 'recondite', 'matter', 'to', 'us', 'his', 'grey', 'eyes', 'shone', 'and']
['twinkled', 'and', 'his', 'usually', 'pale', 'face', 'was', 'flushed', 'and', 'animated', 'the']
def tokenize(lines, token='word'): #@save
"""Metin satırlarını kelime veya karakter belirteçlerine ayırın."""
if token == 'word':
return [line.split() for line in lines]
elif token == 'char':
return [list(line) for line in lines]
else:
print('ERROR: unknown token type: ' + token)
tokens = tokenize(lines)
for i in range(11):
print(tokens[i])
['the', 'time', 'machine', 'by', 'h', 'g', 'wells']
[]
[]
[]
[]
['i']
[]
[]
['the', 'time', 'traveller', 'for', 'so', 'it', 'will', 'be', 'convenient', 'to', 'speak', 'of', 'him']
['was', 'expounding', 'a', 'recondite', 'matter', 'to', 'us', 'his', 'grey', 'eyes', 'shone', 'and']
['twinkled', 'and', 'his', 'usually', 'pale', 'face', 'was', 'flushed', 'and', 'animated', 'the']
8.2.3. Kelime Dağarcığı¶
Andıcın dizgi tipi, sayısal girdiler alan modeller tarafından kullanılmak için elverişsizdir. Şimdi dizgi andıçlarını 0’dan başlayan sayısal indekslere eşlemek için, genellikle kelime dağarcığı olarak adlandırılan bir sözlük oluşturalım. Bunu yapmak için, önce eğitim kümesindeki tüm belgelerdeki benzersiz andıçları, yani bir külliyatı, sayarız ve daha sonra her benzersiz andıca frekansına göre sayısal bir indeks atarız. Genellikle nadiren ortaya çıkan andıçlar karmaşıklığı azaltmak için kaldırılır. Külliyat içinde bulunmayan veya kaldırılan herhangi bir andıç, bilinmeyen özel bir andıç “<unk>” olarak eşleştirilir. İsteğe bağlı olarak, dolgu için “<pad>”, bir dizinin başlangıcını sunmak için “<bos>” ve bir dizinin sonu için “<eos>” gibi ayrılmış andıçların bir listesini ekleriz.
class Vocab: #@save
"""Metin için kelime hazinesi."""
def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
if tokens is None:
tokens = []
if reserved_tokens is None:
reserved_tokens = []
# Frekanslara göre sırala
counter = count_corpus(tokens)
self._token_freqs = sorted(counter.items(), key=lambda x: x[1],
reverse=True)
# Bilinmeyen andıcın indeksi 0'dır
self.idx_to_token = ['<unk>'] + reserved_tokens
self.token_to_idx = {token: idx
for idx, token in enumerate(self.idx_to_token)}
for token, freq in self._token_freqs:
if freq < min_freq:
break
if token not in self.token_to_idx:
self.idx_to_token.append(token)
self.token_to_idx[token] = len(self.idx_to_token) - 1
def __len__(self):
return len(self.idx_to_token)
def __getitem__(self, tokens):
if not isinstance(tokens, (list, tuple)):
return self.token_to_idx.get(tokens, self.unk)
return [self.__getitem__(token) for token in tokens]
def to_tokens(self, indices):
if not isinstance(indices, (list, tuple)):
return self.idx_to_token[indices]
return [self.idx_to_token[index] for index in indices]
@property
def unk(self): # Bilinmeyen andıç için dizin
return 0
@property
def token_freqs(self): # Bilinmeyen andıç için dizin
return self._token_freqs
def count_corpus(tokens): #@save
"""Count token frequencies."""
# Burada `tokens` bir 1B liste veya 2B listedir
if len(tokens) == 0 or isinstance(tokens[0], list):
# Bir belirteç listelerinin listesini belirteç listesine düzleştirin
tokens = [token for line in tokens for token in line]
return collections.Counter(tokens)
Zaman makinesi veri kümesini külliyat olarak kullanarak bir kelime dağarcığı oluşturuyoruz. Daha sonra ilk birkaç sık andıcı dizinleriyle yazdırıyoruz.
vocab = Vocab(tokens)
print(list(vocab.token_to_idx.items())[:10])
[('<unk>', 0), ('the', 1), ('i', 2), ('and', 3), ('of', 4), ('a', 5), ('to', 6), ('was', 7), ('in', 8), ('that', 9)]
vocab = Vocab(tokens)
print(list(vocab.token_to_idx.items())[:10])
[('<unk>', 0), ('the', 1), ('i', 2), ('and', 3), ('of', 4), ('a', 5), ('to', 6), ('was', 7), ('in', 8), ('that', 9)]
vocab = Vocab(tokens)
print(list(vocab.token_to_idx.items())[:10])
[('<unk>', 0), ('the', 1), ('i', 2), ('and', 3), ('of', 4), ('a', 5), ('to', 6), ('was', 7), ('in', 8), ('that', 9)]
Şimdi her metin satırını sayısal indekslerin bir listesine dönüştürebiliriz.
for i in [0, 10]:
print('words:', tokens[i])
print('indices:', vocab[tokens[i]])
words: ['the', 'time', 'machine', 'by', 'h', 'g', 'wells']
indices: [1, 19, 50, 40, 2183, 2184, 400]
words: ['twinkled', 'and', 'his', 'usually', 'pale', 'face', 'was', 'flushed', 'and', 'animated', 'the']
indices: [2186, 3, 25, 1044, 362, 113, 7, 1421, 3, 1045, 1]
for i in [0, 10]:
print('words:', tokens[i])
print('indices:', vocab[tokens[i]])
words: ['the', 'time', 'machine', 'by', 'h', 'g', 'wells']
indices: [1, 19, 50, 40, 2183, 2184, 400]
words: ['twinkled', 'and', 'his', 'usually', 'pale', 'face', 'was', 'flushed', 'and', 'animated', 'the']
indices: [2186, 3, 25, 1044, 362, 113, 7, 1421, 3, 1045, 1]
for i in [0, 10]:
print('words:', tokens[i])
print('indices:', vocab[tokens[i]])
words: ['the', 'time', 'machine', 'by', 'h', 'g', 'wells']
indices: [1, 19, 50, 40, 2183, 2184, 400]
words: ['twinkled', 'and', 'his', 'usually', 'pale', 'face', 'was', 'flushed', 'and', 'animated', 'the']
indices: [2186, 3, 25, 1044, 362, 113, 7, 1421, 3, 1045, 1]
8.2.4. Her Şeyi Bir Araya Koymak¶
Yukarıdaki işlevleri kullanarak, corpus
’u (külliyat), andıç
indekslerinin bir listesidir, ve vocab
’ı döndüren
load_corpus_time_machine
işlevine her şeyi paketliyoruz. Burada
yaptığımız değişiklikler şunlardır: (i) Metni daha sonraki bölümlerdeki
eğitimi basitleştirmek için kelimelere değil, karakterlere andıçlıyoruz;
(ii) corpus
tek bir listedir, andıç listelerinin listesi değildir,
çünkü zaman makinesi veri kümesindeki her metin satırı mutlaka bir cümle
veya paragraf değildir.
def load_corpus_time_machine(max_tokens=-1): #@save
"""Andıç indislerini ve zaman makinesi veri kümesinin kelime dağarcığını döndür."""
lines = read_time_machine()
tokens = tokenize(lines, 'char')
vocab = Vocab(tokens)
# Zaman makinesi veri kümesindeki her metin satırı mutlaka bir cümle veya
# paragraf olmadığından, tüm metin satırlarını tek bir listede düzleştirin
corpus = [vocab[token] for line in tokens for token in line]
if max_tokens > 0:
corpus = corpus[:max_tokens]
return corpus, vocab
corpus, vocab = load_corpus_time_machine()
len(corpus), len(vocab)
(170580, 28)
def load_corpus_time_machine(max_tokens=-1): #@save
"""Andıç indislerini ve zaman makinesi veri kümesinin kelime dağarcığını döndür."""
lines = read_time_machine()
tokens = tokenize(lines, 'char')
vocab = Vocab(tokens)
# Zaman makinesi veri kümesindeki her metin satırı mutlaka bir cümle veya
# paragraf olmadığından, tüm metin satırlarını tek bir listede düzleştirin
corpus = [vocab[token] for line in tokens for token in line]
if max_tokens > 0:
corpus = corpus[:max_tokens]
return corpus, vocab
corpus, vocab = load_corpus_time_machine()
len(corpus), len(vocab)
(170580, 28)
def load_corpus_time_machine(max_tokens=-1): #@save
"""Andıç indislerini ve zaman makinesi veri kümesinin kelime dağarcığını döndür."""
lines = read_time_machine()
tokens = tokenize(lines, 'char')
vocab = Vocab(tokens)
# Zaman makinesi veri kümesindeki her metin satırı mutlaka bir cümle veya
# paragraf olmadığından, tüm metin satırlarını tek bir listede düzleştirin
corpus = [vocab[token] for line in tokens for token in line]
if max_tokens > 0:
corpus = corpus[:max_tokens]
return corpus, vocab
corpus, vocab = load_corpus_time_machine()
len(corpus), len(vocab)
(170580, 28)
8.2.5. Özet¶
Metin, dizi verilerinin önemli bir biçimidir.
Metni ön işlemek için genellikle metni andıçlara böleriz, andıç dizgilerini sayısal indekslere eşlemek için bir kelime dağarcığı oluştururuz ve modellerin işlenmesi için metin verilerini andıç dizinlerine dönüştürürüz.
8.2.6. Alıştırmalar¶
Andıçlama önemli bir ön işleme adımıdır. Farklı diller için değişiktir. Metni andıçlamak için yaygın olarak kullanılan üç yöntem daha bulmaya çalışın.
Bu bölümün deneyinde, metni sözcüklere andıçlayın ve
Vocab
örneğininmin_freq
argümanlarını değiştirin. Bu, kelime dağarcığı boyutunu nasıl etkiler?