Anasayfa / Uygulamalar / R / R ile Metin Madenciliği | Bölüm 5/6

R ile Metin Madenciliği | Bölüm 5/6

5. Bölüm – Düzenli Olmayan Veri Formatını Dönüştürme

Önceki bölümlerde, unnest_tokens işlevi tarafından düzenli metin formatına getirilmiş metinleri analiz ettik. Ayrıca metin verilerini keşfetmek ve görselleştirmek için dplyr, tidyr ve ggplot2 gibi araçlar ile analizlerimizi zenginleştirdik.

Yukarıdaki şema tipik bir metin analizinin akış şemasıdır. Bu bölümde döküman-terim matrisleri ve düzenli veri setleri arasında dönüştürme ve bir Corpus nesnesinden bir metin veri çerçevesine dönüştürme işleminin nasıl yapıldığını gösterir.

Şema analizin düzenli ve düzenli olmayan veri yapıları ve araçları arasında nasıl değişebileceğini göstermektedir. Bu bölümde döküman-terim matrislerini toplama sürecinin yanı sıra bir veri çerçevesini seyrek bir matrise dönüştürme üzerinde durulacaktır.

5.1. Döküman-Terim Matrisini Düzenli Hale Getirme

Metin madenciliği paketlerinin birlikte kullanıldığı en yaygın yapılardan biri döküman-terim matrisidir (Document-Term Matrix, DTM).

  • Her bir satır kitap veya makale gibi bir belgeyi temsil eder.
  • Her bir sütun bir terimi temsil eder ve
  • Her bir değer bir belgedeki bir terimin görüntülenme sayısını içerir.

Çoğu döküman-terim çifti meydana gelmediğinden, DTM’ler genellikle seyrek matrisler olarak işlenir. Bu nesneler matrisler gibi ele alınabilir, ancak daha verimli bir biçimde saklanırlar.

Bu bölümde bu matrislerin birkaç uygulaması anlatılacaktır.

DTM nesneleri doğrudan düzenli veri araçları ile kullanılamaz. Bu yüzden tidytext paketi iki format arasında dönüşüm sağlar.

  • tidy() döküman-terin matrisini düzenli bir veri çerçevesine dönüştürür. Bu fonksiyon “broom” paketinin bir fonksiyonudur.
  • cast() sıralı bir veri çerçevesini matris haline getirir. : tidytext matris dönüştürmede üç farklı varyasyona sahiptir. “Matrix” paketinden cast_sparse() fonksiyonu ile matrisi seyrek matrise dönüştürür. cast_dtm() ise “tm” paketi ile Document-Term Matrix nesnesine dönüştürür.

5.1.1. Döküman-Terim Matrisi Nesnelerini Düzenli Hale Getirme

Muhtemelen en yaygın kullanılan DTM’lerin R’de uygulanması tm paketindeki DocumentTermMatrix fonksiyonudur. Birçok mevcut metin madenciliği veri seti bu biçimde oluşturulmuştur. topicmodels paketinde yer alan Associated Press gazetesinin makalelerini işlemek istersek;

library(tm)

data("AssociatedPress", package = "topicmodels")
AssociatedPress
## <<DocumentTermMatrix (documents: 2246, terms: 10473)>>
## Non-/sparse entries: 302031/23220327
## Sparsity           : 99%
## Maximal term length: 18
## Weighting          : term frequency (tf)

Bu veri kümesinin dökümanları ve terimleri içerdiğini görüyoruz. Buradaki DTM’nin %99’un seyrek (sparse) olduğuna dikkat etmemiz gerekir. Yani döküman-kelime çiftlerinin %99’u sıfırdır. Dökümandaki terimlere Terms() fonksiyonu ile erişebiliriz .

terms <- Terms(AssociatedPress)
head(terms)
## [1] "aaron"      "abandon"    "abandoned"  "abandoning" "abbott"    
## [6] "abboud"

Buradaki verileri düzenli araçlarla analiz etmek istersek broom paketindeki tidy() fonksiyonunu kullanabiliriz. tidy() düzenli olmayan nesneleri düzenli hale getirir.

library(dplyr)
library(tidytext)

ap_td <- tidy(AssociatedPress)
ap_td
## # A tibble: 302,031 x 3
##    document term       count
##       <int> <chr>      <dbl>
##  1        1 adding         1
##  2        1 adult          2
##  3        1 ago            1
##  4        1 alcohol        1
##  5        1 allegedly      1
##  6        1 allen          1
##  7        1 apparently     2
##  8        1 appeared       1
##  9        1 arrested       1
## 10        1 assault        1
## # ... with 302,021 more rows

Çıktının sıfır olmayan değerleri içerdiğine dikkat edelim.“adding” ve “adult” gibi terimleri karşımızda görüyoruz, ancak yukarıdaki terms çıktısındaki “aaron” veya “abondon” ifadelerini göremiyoruz. Bu da, düzenli formatın satırlarında sıfır olan değerler içermediği anlamına gelir.

Daha önceki bölümlerde de gördüğümüz gibi, elde ettiğimiz elde ettiğimiz bu form dplyr, tidytext ve ggplot2 paketleri ile analiz için uygundur. Şimdi duygu analizi yapmak istersek,

ap_sentiments <- ap_td %>%
  inner_join(get_sentiments("bing"), by = c(term = "word"))

ap_sentiments
## # A tibble: 30,094 x 4
##    document term    count sentiment
##       <int> <chr>   <dbl> <chr>    
##  1        1 assault     1 negative 
##  2        1 complex     1 negative 
##  3        1 death       1 negative 
##  4        1 died        1 negative 
##  5        1 good        2 positive 
##  6        1 illness     1 negative 
##  7        1 killed      2 negative 
##  8        1 like        2 positive 
##  9        1 liked       1 positive 
## 10        1 miracle     1 positive 
## # ... with 30,084 more rows

Associated Press’deki kelimelerden hangilerinin olumlu ya da olumsuz duygulara katkıda bulunduğunu aşağıda görselleştirelim.

library(ggplot2)

ap_sentiments %>%
  count(sentiment, term, wt = count) %>%
  ungroup() %>%
  filter(n >= 200) %>%
  mutate(n = ifelse(sentiment == "negative", -n, n)) %>%
  mutate(term = reorder(term, n)) %>%
  ggplot(aes(term, n, fill = sentiment)) +
  geom_bar(stat = "identity") +
  ylab("Contribution to sentiment") +
  coord_flip()

Bing duygu sözlüğü ile en çok kullanılan olumlu kelimelerin “like”, “work”, “support” ve “good” olduğunu, en olumsuz kelimelerin ise “killed”, “death” ve “vice” olduğunu görüyoruz.

5.1.2. Döküman-Özellik Matrisi (DFM – Document-Feature Matrix) Nesnelerini Düzenli Hale Getirme

Diğer bir metin madenciliği paketi olan “quanteda” paketi alternatif bir döküman-terim matrisi uygulaması olarak döküman-özellik matrisini (document-feature matrix – dfm) sunar.

quanteda paketi dfm ile ABD başkanlık meclis açılış konuşmalarını analiz edeim.

data("data_corpus_inaugural", package = "quanteda")
inaug_dfm <- quanteda::dfm(data_corpus_inaugural, verbose = FALSE)

inaug_dfm
## Document-feature matrix of: 58 documents, 9,405 features (91.8% sparse).

tidy() fonksiyonu döküman-özellik matrisi ile de çalışır.

inaug_td <- tidy(inaug_dfm)
inaug_td
## # A tibble: 44,895 x 3
##    document        term            count
##    <chr>           <chr>           <dbl>
##  1 1789-Washington fellow-citizens     1
##  2 1797-Adams      fellow-citizens     3
##  3 1801-Jefferson  fellow-citizens     2
##  4 1809-Madison    fellow-citizens     1
##  5 1813-Madison    fellow-citizens     1
##  6 1817-Monroe     fellow-citizens     5
##  7 1821-Monroe     fellow-citizens     1
##  8 1841-Harrison   fellow-citizens    11
##  9 1845-Polk       fellow-citizens     1
## 10 1849-Taylor     fellow-citizens     1
## # ... with 44,885 more rows

Açılış konuşmalarının her birine özgü kelimeleri bulmak ilgimizi çekebilir. Bunu da bind_tf_idf() ile tf-idf’in hesaplanmasıyla ölçülebilir .

inaug_tf_idf <- inaug_td %>%
  bind_tf_idf(term, document, count) %>%
  arrange(desc(tf_idf))

inaug_tf_idf
## # A tibble: 44,895 x 6
##    document        term        count      tf   idf tf_idf
##    <chr>           <chr>       <dbl>   <dbl> <dbl>  <dbl>
##  1 1793-Washington arrive          1 0.00680  4.06 0.0276
##  2 1793-Washington upbraidings     1 0.00680  4.06 0.0276
##  3 1793-Washington violated        1 0.00680  3.37 0.0229
##  4 1793-Washington willingly       1 0.00680  3.37 0.0229
##  5 1793-Washington incurring       1 0.00680  3.37 0.0229
##  6 1793-Washington previous        1 0.00680  2.96 0.0201
##  7 1793-Washington knowingly       1 0.00680  2.96 0.0201
##  8 1793-Washington injunctions     1 0.00680  2.96 0.0201
##  9 1793-Washington witnesses       1 0.00680  2.96 0.0201
## 10 1793-Washington besides         1 0.00680  2.67 0.0182
## # ... with 44,885 more rows

Bu veriden ABD Başkanları Lincoln, Roosevelt, Kennedy ve Obama’yı karşılaştırmak iiçn görselleştirme yapalım.

ABD Başkanlarının konuşmalarındaki en yüksek tf-idf’ye sahip kelimeler,

inaug_tf_idf %>% filter(document %in% c("1861-Lincoln","1933-Roosevelt","1961-Kennedy","2009-Obama")) %>% 
  arrange(desc(tf_idf)) %>%
  mutate(term = factor(term, levels = rev(unique(term)))) %>% 
  group_by(document) %>% 
  top_n(15) %>% 
  ungroup %>%
  ggplot(aes(term, tf_idf, fill = document)) +
  geom_col(show.legend = FALSE) +
  labs(x = NULL, y = "tf-idf") +
  facet_wrap(~document, ncol = 2, scales = "free") +
  coord_flip()
## Selecting by tf_idf

Düzenli verilerle mümkün olan bir görselleştirme örneği daha yapalım. Her bir belgenin yıllara göre ayrılmasıyla, hey yıl içerisindeki toplam kelime sayısını gösterelim.

Tidyr’in complete() fonksiyonunu, veri setindeki sıfırları (yani bir kelimenin bir dökümanda görünmediği durumlar) içerecek şekilde kullandığımızı unutmayalım.

library(tidyr)

year_term_counts <- inaug_td %>%
  extract(document, "year", "(\d+)", convert = TRUE) %>%
  complete(year, term, fill = list(count = 0)) %>%
  group_by(year) %>%
  mutate(year_total = sum(count))

Bu da kelimeleri seçmemize ve aşağıdaki grafikteki gibi zaman içinde frekansların nasıl değiştiklerini görselleştimemize olanak tanır. Zaman içinde Amerikan Başanlarının ülkeye “Union” yani “Birlik” olarak gönderme yapma ihtimalinin düşük olduğunu ve “America” için gönderme yapma olasılıklarının daha yüksek olduğunu görebiliriz. Ayrıca “constitution” (“anayasa”) ve “foreign” (“yabancı”) ülkeler hakkında ve “fredom” (“özgürlük”) ve “God” (“Tanrı”) ’dan söz etme olasılıklarının daha düşük olduğu da görülüyor.

year_term_counts %>%
  filter(term %in% c("god", "america", "foreign", "union", "constitution", "freedom")) %>%
  ggplot(aes(year, count / year_total)) +
  geom_point() +
  geom_smooth() +
  facet_wrap(~ term, scales = "free_y") +
  scale_y_continuous(labels = scales::percent_format()) +
  ylab("% frequency of word in inaugural address")
## geom_smooth() using method = 'loess' and formula 'y ~ x'

Yukarıdaki grafik ABD Başkanlık açılış konuşmalarında zaman içinde kullanılan kelime sıklığındaki değişikliklerdir.

Bu örnekler ile veri kaynakları düzenli bir biçimde olmasa bile veri kaynaklarını analiz etmek için tidytext’i ve ilgili diğer düzenleme araçları (tidy tools) nasıl kullanabileceğinizi göstermektedir.

5.2. Düzenli Metni Bir Matrise Aktarmak

Bazı metin madenciliği paketleri, örnek veri veya çıktı olarak doküman-terim matrisleri sağladığından, bazı algoritmalar bu matrisleri girdi olarak bekler. Bu nedenle, cast_ ile tidytext düzenli bir formdan bu matrislere dönüştürmek için işlevler sağlar .

Örneğin, düzenli hale getirilmiş Associated Press veri kümesini ele alıp, cast_dtm() fonksiyonu ile doküman-terim matrisine geri gönderebiliriz .

ap_td %>%
  cast_dtm(document, term, count)
## Warning: Trying to compute distinct() for variables not found in the data:
## - row_col, column_col
## This is an error, but only a warning is raised for compatibility reasons.
## The operation will return the input unchanged.
## <<DocumentTermMatrix (documents: 2246, terms: 10473)>>
## Non-/sparse entries: 302031/23220327
## Sparsity           : 99%
## Maximal term length: 18
## Weighting          : term frequency (tf)

Benzer bir şekilde, veriyi cast_dfm() fonksiyonu ile bir dfm nesnesine dönüştürbiliiz.

ap_td %>%
  cast_dfm(document, term, count)
## Warning: Trying to compute distinct() for variables not found in the data:
## - row_col, column_col
## This is an error, but only a warning is raised for compatibility reasons.
## The operation will return the input unchanged.
## Document-feature matrix of: 2,246 documents, 10,473 features (98.7% sparse).

Bazı yöntemler için sadece seyrek (sparse) bir matris gerekir.

library(Matrix)

# Matris nesnesine aktarma
m <- ap_td %>%
  cast_sparse(document, term, count)
## Warning: Trying to compute distinct() for variables not found in the data:
## - row_col, column_col
## This is an error, but only a warning is raised for compatibility reasons.
## The operation will return the input unchanged.
class(m)
## [1] "dgCMatrix"
## attr(,"package")
## [1] "Matrix"
dim(m)
## [1]  2246 10473

Bu tür dönüşümler, şuana kadar kullandığımız düzenli metin yapılarından kolayca yapılabilir. Örneğin, Jane Austen’in kitaplarının sadece birkaç satırında bir DTM oluşturmak istersek;

library(janeaustenr)

austen_dtm <- austen_books() %>%
  unnest_tokens(word, text) %>%
  count(book, word) %>%
  cast_dtm(book, word, n)
## Warning: Trying to compute distinct() for variables not found in the data:
## - row_col, column_col
## This is an error, but only a warning is raised for compatibility reasons.
## The operation will return the input unchanged.
austen_dtm
## <<DocumentTermMatrix (documents: 6, terms: 14520)>>
## Non-/sparse entries: 40379/46741
## Sparsity           : 54%
## Maximal term length: 19
## Weighting          : term frequency (tf)

cast süreci dplyr ve diğer tidy tools (düzenli araçlar) ile veri üzerinde tarama, filtreleme ve işleme yapılmasına izin verir. Bu işlemlerden sonra, veriler, makine öğrenimi uygulamaları için bir doküman-terim matrisine dönüştürülebilir. 6. Bölümde, düzenli metin veri setini işlemek için bir Document-Term Matrix’e dönüştürülmesi gereken bazı örnekleri inceleyeceğiz.

5.3. Meta Veri ile Korpus Nesnelerini Düzenleme

Bazı veri yapıları , genellikle “corpus” (korpus) olarak adlandırılan ve parçalara ayırmadan önce döküman koleksiyonlarını depolamak için tasarlanmıştır.

tm paketinden yaygın bir örnek olark korpus nesnelerine bakalım. İnceleyeceğimiz metin , her bir döküman için bir kimlik numarası (ID), tarih (date) / zaman (time), başlık (title) veya dil (language) içerebilen meta verileri depolar.

Örnek olarak, tm paketinden acq verisi, haber servisi Reuters’ten 50 makale içeren korpus ile birlikte gelir.

data("acq")
acq
## <<VCorpus>>
## Metadata:  corpus specific: 0, document level (indexed): 0
## Content:  documents: 50

Bir korpus nesnesi, hem metin hem de meta veri içeren bir liste gibi yapılandırılmıştır. Bu da dökümanlar için esnek bir depolama yöntemidir, ancak düzenli araçlarla işlenmesine katkıda bulunmaz.

Böylelikle tidy() fonksiyonu ile meta verileri döküman başına bir satır olarak oluşturalım.

acq_td <- tidy(acq)
acq_td
## # A tibble: 50 x 16
##    author  datetimestamp       description heading   id    language origin
##    <chr>   <dttm>              <chr>       <chr>     <chr> <chr>    <chr> 
##  1 <NA>    1987-02-26 17:18:06 ""          COMPUTER… 10    en       Reute…
##  2 <NA>    1987-02-26 17:19:15 ""          OHIO MAT… 12    en       Reute…
##  3 <NA>    1987-02-26 17:49:56 ""          MCLEAN'S… 44    en       Reute…
##  4 By Cal… 1987-02-26 17:51:17 ""          CHEMLAWN… 45    en       Reute…
##  5 <NA>    1987-02-26 18:08:33 ""          <COFAB I… 68    en       Reute…
##  6 <NA>    1987-02-26 18:32:37 ""          INVESTME… 96    en       Reute…
##  7 By Pat… 1987-02-26 18:43:13 ""          AMERICAN… 110   en       Reute…
##  8 <NA>    1987-02-26 18:59:25 ""          HONG KON… 125   en       Reute…
##  9 <NA>    1987-02-26 19:01:28 ""          LIEBERT … 128   en       Reute…
## 10 <NA>    1987-02-26 19:08:27 ""          GULF APP… 134   en       Reute…
## # ... with 40 more rows, and 9 more variables: topics <chr>,
## #   lewissplit <chr>, cgisplit <chr>, oldid <chr>, places <list>,
## #   people <lgl>, orgs <lgl>, exchanges <lgl>, text <chr>

Bundan sonra unnest_tokens() ile 50 Reuters makalesindeki veya her makaledeki özgü olanlarda en yaygın kelimeleri bulalım.

acq_tokens <- acq_td %>%
  select(-places) %>%
  unnest_tokens(word, text) %>%
  anti_join(stop_words, by = "word")

# en yaygın kelimeler
acq_tokens %>%
  count(word, sort = TRUE)
## # A tibble: 1,566 x 2
##    word         n
##    <chr>    <int>
##  1 dlrs       100
##  2 pct         70
##  3 mln         65
##  4 company     63
##  5 shares      52
##  6 reuter      50
##  7 stock       46
##  8 offer       34
##  9 share       34
## 10 american    28
## # ... with 1,556 more rows
# tf-idf
acq_tokens %>%
  count(id, word) %>%
  bind_tf_idf(word, id, n) %>%
  arrange(desc(tf_idf))
## # A tibble: 2,853 x 6
##    id    word         n     tf   idf tf_idf
##    <chr> <chr>    <int>  <dbl> <dbl>  <dbl>
##  1 186   groupe       2 0.133   3.91  0.522
##  2 128   liebert      3 0.130   3.91  0.510
##  3 474   esselte      5 0.109   3.91  0.425
##  4 371   burdett      6 0.103   3.91  0.405
##  5 442   hazleton     4 0.103   3.91  0.401
##  6 199   circuit      5 0.102   3.91  0.399
##  7 162   suffield     2 0.1     3.91  0.391
##  8 498   west         3 0.1     3.91  0.391
##  9 441   rmj          8 0.121   3.22  0.390
## 10 467   nursery      3 0.0968  3.91  0.379
## # ... with 2,843 more rows

5.4. Özet

Metin analizinde çoğunlukla düzenli bir yapıda olmayan verileri, çeşitli araçlarla düzenli hale getirmeyi amaçlanır. Bu bölümde, düzenli bir metin veri çerçevesi ve seyrek döküman-terim matrisleri arasında nasıl dönüştürüleceğini ve döküman meta verilerini içeren bir korpus nesnesinin nasıl düzenli hale getirileceği anlatılmıştır.

Bir sonraki bölüm, bahsi geçen dönüştürme araçlarının metin analizinin önemli bir parçası olduğunu anlayacağımız bir bölüm olacak.

Hakkında Ekrem Bayar

GÖZ ATMAK İSTEYEBİLİRSİNİZ

R ile Sıralı Logit Modelleri

Herkese merhaba, bu yazıda sıralı logit modelleri ve bu modellerin tahmincileri üzerine bir uygulama yapacağız. …

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir