Ana içeriğe geç

R ile NLP ve Makine Öğrenimi ile Şarkı Sözü Analizi

Prince’in müziğinin şarkı sözlerine R ile dalın: metin madenciliği ve Keşifsel Veri Analizi (EDA) kullanarak The Artist’ın kariyerine ışık tutun.
· 15 dk. oku

Yapay Zeka ile Keşfedin

Bu, efsanevi sanatçı Prince’in şarkı sözleri üzerine bir vaka çalışmasında R kullanarak çeşitli analitik görevler yapacağınız, üç bölümlük bir eğitim serisinin Birinci Bölümü. Üç eğitim şu konuları kapsar:

nlp R

Giriş

Müzik sözleri bir sanatçının bakış açısını yansıtabilir, ancak popüler şarkılar toplumun duymak istediklerini ortaya koyar. Şarkı sözü analizi kolay bir iş değildir. Düz yazıdan çok farklı yapılandığı için varsayımlarda dikkatli olmayı ve özgün bir analitik teknik seçimini gerektirir. Şarkı sözleri hayatımıza sızar ve düşüncelerimizi fark edilmeden etkiler. Öngörücü Şarkı Sözleri kavramı yeni yeni konuşulmaya başlandı ve araştırma makaleleri ile lisansüstü tezlerde giderek daha çok yer buluyor. Bu vaka çalışması, bu gelişmekte olan konunun yalnızca birkaç yönüne değinecek.

Prince: Sanatçı

Prince’in geride bıraktığı ilham verici ve çeşitli eserlerini kutlamak için, sözlerinde bazen açık, çoğu zaman gizli mesajları keşfedeceksiniz. Yine de, dünya çapında pek çok türün gelişimindeki etkisini takdir etmek için Prince’in müziğini sevmeniz gerekmez. Rolling Stone dergisi, Prince’i tüm zamanların en iyi 18. söz yazarı olarak, Bob Dylan, John Lennon, Paul Simon, Joni Mitchell ve Stevie Wonder gibi isimlerin hemen arkasında listeler. Şarkı sözü analizi, "Hit Şarkıları" öngörme olasılığı gerçeğe yaklaşırken yavaş yavaş veri bilimi topluluklarında yer buluyor.

Prince müzikle taşan bir adamdı — çılgınca üretken bir söz yazarı, gitarlar, klavyeler ve davullarda virtüöz ve müziği türleri aşıyor olsa da funk, rock, R&B ve pop’un usta bir mimarı. - Jon Pareles (NY Times)

Bu eğitimin, serinin Birinci Bölümü olan kısmında, tidy text çerçevesini kullanarak bir dizi şarkı sözü üzerinde metin madenciliği tekniklerinden yararlanacaksınız. Tidy veri setlerinin belirli bir yapısı vardır: her değişken bir sütun, her gözlem bir satır ve her gözlemsel birim türü bir tablodur. Veri setini temizleyip koşullandırdıktan sonra, Prince’in şarkı sözlerinin farklı yönlerine bakarken betimsel istatistikler ve keşifsel görselleştirmeler oluşturacaksınız.

Önkoşullar

Bu eğitim serisinin Birinci Bölümü, tidy veriye ilişkin temel bir anlayış gerektirir — özellikle veri dönüşümü için dplyr, görselleştirmeler için ggplot2 ve kökeni magrittr paketine dayanan %>% pipe operatörü gibi paketler. Her eğitim, analizinizde kullanabileceğiniz araçları tanıtacak, ancak her adımı ayrıntılandırmayabilir. Birçok adımın genellikle %>% operatörüyle birleştirildiğini fark edeceksiniz. Bu aynı zamanda bir vaka çalışması olduğundan, yaptığınız tüm çıkarımların tamamen gözlemsel olduğunu unutmamak önemlidir; dolayısıyla, korelasyon nedenselliği ima etmez.

İpucu: kullanılan araçlar hakkında arka plan için iki iyi kaynak: Garrett Grolemund ve Hadley Wickham’ın R for Data Science’ı; ve Julia Silge ile David Robinson’ın Text Mining with R’ı.

İkinci ve Üçüncü Bölümler

Ayrı bir eğitim olan İkinci Bölüm’de, Prince’in müziğindeki genel ruh halini ve temaları ve bunların toplumsal bakış açılarına uygulanışını yakalamak için Duygu Analizi ve Konu Modellemesini ele alacaksınız. Bir duygu sözlüğü ile çalışacak, ikili ve kategorik duyguları değerlendirecek, zaman içindeki eğilimleri çizecek ve n-gram’lar ile sözcük birlikteliklerine bakacaksınız. Ayrıca Doğal Dil İşleme (NLP) ve Gizli Dirichlet Ayrımı (LDA) ile K-Ortalamalar gibi kümeleme tekniklerini kullanarak sözlerdeki motifleri ortaya çıkaracaksınız.

Bir diğer eğitim olan Üçüncü Bölüm’de ise, keşifsel sonuçlarınızı kullanarak bir şarkının hangi on yılda yayımlandığını ve daha da ilginci, yalnızca sözlerine bakarak Billboard listelerine girip girmeyeceğini tahmin etmeye çalışarak işi tamamlayacaksınız. Karar Ağaçları (rpart ve C50), En Yakın K-Komşular (class) ve Naive Bayes (e1071) gibi makine öğrenimi araçlarını kullanarak metin kabul edebilen bir sınıflandırıcı üreteceksiniz.

Üç bölümün tamamı, Prince’in şarkı sözleri, yayımlanma yılı ve Billboard liste konumlarından oluşan aynı veri setini kullanacaktır. Bu çalışmadaki teknikler, pek çok başka metin türüne de uygulanabilir. Aslında, standart düzyazı için sonuçlar genellikle daha kolay yorumlanır çünkü şarkı sözleri genel olarak dolaylı mesajlar ve ince nüanslarla tasarlanır.

Özetle, şarkı sözlerini analiz etmek için birçok farklı yöntem vardır. Bu eğitimler, aşağıdaki görselde kırmızıyla vurgulananları kapsar. Bu görselin çok "bulanık" bir resmin yalnızca üst düzey bir temsil olduğunu unutmayın. Ve hayır, kastettiğim görselin kendisi değil! Gerçek şu ki, modelleme ve makine öğrenimi tekniklerinin farklı yönleri artık bulanıklaşmış durumda ve aşağıda gösterildiği gibi tek bir kutuya sığmayabiliyor. Bu yüzden görsele bakarken 3D gözlükleri takın; belki daha anlamlı gelir!

Kullanılan Araçlar
Burada sunulan görselden uyarlanmıştır here

Hedefler

Yeni beceriler öğrenip pratiğini yapmanın yanı sıra, bu eğitim şarkı sözü analizi kavramıyla ilgili temel soruları ele almayı amaçlar. Son çalışmalar, popüler müzikte "sözel zekânın" düşüşte olabileceğini gösteriyor. Bazı çalışmalar, 1 Numaralı Hit Şarkılarda kullanılan kelimelerin ABD’de 3. sınıf öğrencilerinin okuma seviyeleriyle örtüştüğünü dahi öne sürüyor. Böyle bir konuya ışık tutmak için metin madenciliği, NLP, makine öğrenimi ve diğer veri bilimi yöntemlerinden yararlanmak mümkün mü? Bir şarkının nasıl karşılandığına bağlı olarak topluma hitap eden temaları belirlemek mümkün mü? Sadece söz analizine dayanarak bir şarkının başarılı olup olmayacağını tahmin etmek mümkün mü? Bu ilk eğitimde, Prince’in müziğinin sözel karmaşıklığını keşif amaçlı inceleyeceksiniz.

Sorular

Dalmadan önce, neyi keşfetmeye çalıştığınızı düşünün. Hangi sorular ilginizi çekiyor? Önce veri setinin bir analizini adım adım yapacaksınız. Nasıl görünüyor? Kaç şarkı var? Sözler nasıl yapılandırılmış? Ne kadar temizlik ve düzenleme gerekiyor? Gerçekler neler? Kelime sıklıkları nedir ve bu neden önemli? Teknik açıdan, veriyi duygu analizi, NLP ve makine öğrenimi modelleri için anlamak ve hazırlamak istersiniz.

Müzik uzun zamandır kitlelere iletişim kurmanın etkili bir yolu oldu ve şarkı sözleri bu iletişimi iletmede büyük bir rol oynadı. Yine de [toplumun] esenliğinde sözlerin rolüne dair araştırma fırsatı büyük ölçüde yeterince kullanılmıyor. - Patricia Fox Ransom

Veri

Metin madenciliği için veri elde etmenin popüler bir yöntemi, rvest paketini kullanarak web’den içerik kazımaktır. Billboard Liste bilgilerini ve Prince’in şarkı sözlerini çeşitli sitelerden kazıyıp şarkı başlıklarında birleştirebildim. Başlıklar için tutarsız adlandırma kuralları olduğundan biraz düzenleme gerekti. Ardından, orijinal sürüm olmayan, yani remiksler, uzatılmış sürümler, kulüp miksleri, yeniden yapımlar vb. tüm şarkıları kaldırma yönünde öznel bir karar verdim. Ayrıca tekrarları önlemek için Hit Şarkılarının tarihsel derlemelerini içeren albümleri de çıkardım. Biraz küçük temizlik yapıp sonucu bu eğitimde kullanılabilecek bir csv dosyasına kaydettim.

Birinci Bölüm metin madenciliğine odaklandığından, bu eğitim için o kodu dahil etmedim; ancak veri setini indirmek isterseniz buradan erişebilirsiniz.

Kütüphaneleri yükleyin

#most of the libraries needed
library(dplyr) #data manipulation
library(ggplot2) #visualizations
library(gridExtra) #viewing multiple plots together
library(tidytext) #text mining
library(wordcloud2) #creative visualizations

Veriyi içe alın

Bir csv dosyasından veri okumak için birkaç yöntem vardır, ancak ben sözleri, yayımlanma yılını ve Billboard liste konumlarını içeren bir veri çerçevesi yüklemek için read.csv() kullanmayı seçtim. Varsayılan olarak R’nin tüm karakter dizilerini faktöre dönüştürdüğüne dikkat edin. Bu, sonraki adımlarda sorun yaratabilir; fakat stringsAsFactors parametresini FALSE yaparak bunu önleyebilirsiniz. Şimdi veriyi inceleyelim…

prince_orig <- read.csv("prince_raw_data.csv", stringsAsFactors = FALSE)

Veri çerçevesindeki sütunları görmek için names() işlevini kullanabilirsiniz:

names(prince_orig)
##  [1] "X"            "text"         "artist"       "song"        
##  [5] "year"         "album"        "Release.Date" "US.Pop"      
##  [9] "US.R.B"       "CA"           "UK"           "IR"          
## [13] "NL"           "DE"           "AT"           "FR"          
## [17] "JP"           "AU"           "NZ"           "peak"

Bu dosyayı ben oluşturduğum için X’in yalnızca bir satır numarası, text’in ise gerçek şarkı sözleri olduğunu biliyorum. Diğer gerekli alanlar arasında şarkı (song), yıl (year) ve Billboard listelerindeki yerini gösteren peak bulunur. US.Pop ve US.R.B, ABD (Pop ve R&B listeleri) için zirve liste konumlarıdır; bunları da koruyun ve şimdilik diğer tüm alanları bırakın.

Bunu, orijinal veri seti olan prince_orig’i alıp %>% ile select()’e aktararak yapın. Böylece kodu soldan sağa okuyabilirsiniz.

Ayrıca, select()’in sütunları tek adımda yeniden adlandırmanıza izin verdiğine dikkat edin. Dolayısıyla text’i lyrics olarak ayarlayın ve US sütunlarını "." yerine "_" kullanarak tidyverse tarzında yeniden adlandırın. Ardından sonucu, eğitim boyunca kullanacağınız prince içinde saklayın. dplyr, verinize transpoze bir görünümde bakmayı kolaylaştıran glimpse() adlı bir işlev sağlar.

prince <- prince_orig %>% 
  select(lyrics = text, song, year, album, peak, 
         us_pop = US.Pop, us_rnb = US.R.B)

glimpse(prince[139,])
Observations: 1
Variables: 7
$ lyrics <chr> "I just can't believe all the things people say, controversy\nAm I ...
$ song   <chr> "controversy"
$ year   <int> 1981
$ album  <chr> "Controversy"
$ peak   <int> 3
$ us_pop <chr> "70"
$ us_rnb <chr> "3"

İlk açık soru: kaç gözlem ve kaç sütun var?

dim(prince)
[1] 824   7

dim() işlevini kullanarak 7 sütun ve 824 gözlem olduğunu görürsünüz. Her gözlem bir şarkıdır. Dediğim gibi… üretken!

Şarkılardan birinin lyrics sütununa baktığınızda, yapının nasıl olduğunu görebilirsiniz.

str(prince[139, ]$lyrics, nchar.max = 300)
 chr "I just can't believe all the things people say, controversy\nAm I Black or White? Am I straight or gay? Controversy\nDo I believe in God? Do I believe in me? Controversy\nControversy, controversy\nI can't understand human curiosity, controversy\nWas it good for you? Was I what you w"| __truncated__

Temizlemek için bolca fırsat var, hadi başlayalım.

Veri Koşullandırma

Temel temizlik

Veriyi koşullandırmak için kullanabileceğiniz farklı yöntemler vardır. Bir seçenek, veri çerçevesini tm metin madenciliği paketiyle bir Korpus ve Belge Terim Matrisi’ne dönüştürmek ve ardından temizlik için tm_map() işlevini kullanmaktır; ancak bu eğitim şimdilik temel konularla sınırlı kalacak ve kirli işleri yapmak için gsub() ve apply() işlevlerini kullanacaktır.

Önce, gsub() kullanarak çoğu senaryoyu ele alan küçük bir işlev oluşturarak o can sıkıcı kısaltmalardan kurtulun ve ardından bu işlevi tüm şarkı sözlerine uygulayın.

# function to expand contractions in an English-language source
fix.contractions <- function(doc) {
  # "won't" is a special case as it does not expand to "wo not"
  doc <- gsub("won't", "will not", doc)
  doc <- gsub("can't", "can not", doc)
  doc <- gsub("n't", " not", doc)
  doc <- gsub("'ll", " will", doc)
  doc <- gsub("'re", " are", doc)
  doc <- gsub("'ve", " have", doc)
  doc <- gsub("'m", " am", doc)
  doc <- gsub("'d", " would", doc)
  # 's could be 'is' or could be possessive: it has no expansion
  doc <- gsub("'s", "", doc)
  return(doc)
}

# fix (expand) contractions
prince$lyrics <- sapply(prince$lyrics, fix.contractions)

Metni bulanıklaştıran özel karakterleri de fark edeceksiniz. Bunları gsub() işlevi ve basit bir düzenli ifadeyle kaldırabilirsiniz. Dikkat: Bu adımdan önce kısaltmaları genişletmek kritik önemdedir!

# function to remove special characters
removeSpecialChars <- function(x) gsub("[^a-zA-Z0-9 ]", " ", x)
# remove special characters
prince$lyrics <- sapply(prince$lyrics, removeSpecialChars)

Tutarlılık için, kullanışlı tolower() işleviyle her şeyi küçük harfe dönüştürün.

# convert everything to lower case
prince$lyrics <- sapply(prince$lyrics, tolower)

Şimdi sözleri incelediğinizde, orijinal ham metnin daha temiz bir sürümünü görürsünüz.

str(prince[139, ]$lyrics, nchar.max = 300)
chr "i just can not believe all the things people say  controversy am i black or white

Metin madenciliği için veriyi koşullandırmadaki bir diğer yaygın adım, kelimeleri kök anlamlarına indirgeme ya da gövdeleme (stemming) olarak adlandırılır. Bu başlı başına bir konu olup daha sonra ele alınabilir. Şimdilik, prince veri çerçevesinin özetine bakın.

#get facts about the full dataset
summary(prince)
    lyrics              song                year         album          
 Length:824         Length:824         Min.   :1978   Length:824        
 Class :character   Class :character   1st Qu.:1989   Class :character  
 Mode  :character   Mode  :character   Median :1996   Mode  :character  
                                       Mean   :1995                     
                                       3rd Qu.:1999                     
                                       Max.   :2015                     
                                       NA's   :495                      
      peak          us_pop             us_rnb         
 Min.   : 0.00   Length:824         Length:824        
 1st Qu.: 2.00   Class :character   Class :character  
 Median : 7.00   Mode  :character   Mode  :character  
 Mean   :15.48                                        
 3rd Qu.:19.00                                        
 Max.   :88.00                                        
 NA's   :751

Gördüğünüz gibi, 37 yıllık şarkı var ve (veri setinde bulunan) en düşük listeye giren şarkı 88. sırada. Ayrıca yıl ve peak için oldukça fazla NA olduğunu da görebilirsiniz. Farklı türde analizler yapacağınız için, tam veri setini prince veri çerçevesinde tutun ve gerektiğinde filtreleyin.

Birkaç alan ekleyin

Hedef sorularınızdan biri zaman içinde şarkı eğilimlerine bakmak olduğundan ve veri setinde tek tek yayımlanma yılları bulunduğundan, yılları on yıllık dilimlere (bucket) ayırabilirsiniz. dplyr’ın mutate() fiilini kullanarak yeni decade alanını oluşturun. Dilimleri oluşturmanın bir yolu, ifelse() ile %in% operatörünü birlikte kullanarak yıllara göre filtreleme ve şarkıları on yıllara göre gruplamaktır. Sonra sonuçları tekrar prince içine yazın (özünde yeni bir alan eklemiş olursunuz).

#create the decade column
prince <- prince %>%
  mutate(decade = 
           ifelse(prince$year %in% 1978:1979, "1970s", 
           ifelse(prince$year %in% 1980:1989, "1980s", 
           ifelse(prince$year %in% 1990:1999, "1990s", 
           ifelse(prince$year %in% 2000:2009, "2000s", 
           ifelse(prince$year %in% 2010:2015, "2010s", 
                  "NA"))))))

Aynısını, bir şarkının Top 10, Top 100’e ulaşıp ulaşmadığını ya da listeye hiç girmediğini (uncharted) ifade eden chart_level için de yapabilirsiniz. Bunlar birbirini dışlar; dolayısıyla Top 100, Top 10 şarkıları içermez.

#create the chart level column
prince <- prince %>%
  mutate(chart_level = 
           ifelse(prince$peak %in% 1:10, "Top 10", 
           ifelse(prince$peak %in% 11:100, "Top 100", "Uncharted")))

Ayrıca, bir şarkının Billboard listelerine girip girmediğini gösteren charted adlı ikili bir alan oluşturun (yani popüler bir şarkı). Sonraki eğitimlerde kullanmak üzere write.csv() ile kaydedin.

#create binary field called charted showing if a song hit the charts at all
prince <- prince %>%
  mutate(charted = 
           ifelse(prince$peak %in% 1:100, "Charted", "Uncharted"))

#save the new dataset to .csv for use in later tutorials
write.csv(prince, file = "prince_new.csv")

Betimsel İstatistikler

Grafikleri özelleştirmek için, görsellerin tutarlı kalması adına benzersiz bir renk listesi oluşturmayı seviyorum. Aşağıdaki gibi onaltılık kod temsilleriyle ayırt edilebilir renkler bulabileceğiniz birçok web kaynağı var. Grafikleriniz için bir tercihiniz varsa, gerektiğinde ggplot()’a uygulayabileceğiniz kendi temanızı da oluşturabilirsiniz.

#define some colors to use throughout
my_colors <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7", "#D55E00")

theme_lyrics <- function() 
{
  theme(plot.title = element_text(hjust = 0.5),
        axis.text.x = element_blank(), 
        axis.ticks = element_blank(),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "none")
}

Metin madenciliğine girmeden önce, verinizin şarkı düzeyinde neler barındırdığına dair temel bir görünümle başlayın. Prince’in on yıllara göre kaç şarkı yayımladığını görselleştirmek için iyi bir zaman. Hatırlatma: profesyonel kariyeri 1978’de başladı ve 2015’e kadar sürdü (yukarıdaki summary() istatistiklerinde gösterildiği gibi). Ancak şimdi eğilimlere baktığımız ve veri setinde yıl için çok sayıda boş değer olduğu için, ilk grafikte yayımlanma yılı NA olanların tümünü filtrelemek isteyeceksiniz.

Şarkı İstatistikleri

dplyr’ın filter(), group_by() ve summarise() işlevlerini kullanarak on yıla göre gruplama yapabilir ve ardından şarkı sayısını sayabilirsiniz. n() işlevi, gruplandırılmış verilerde summarise() ile kullanımı yararlı birkaç toplulaştırma işlevinden biridir. Sonra ggplot() ve geom_bar() kullanarak bir çubuk grafik oluşturun ve çubukları charted kategorisine göre doldurun.

prince %>%
  filter(decade != "NA") %>%
  group_by(decade, charted) %>%
  summarise(number_of_songs = n()) %>%
  ggplot() + 
  geom_bar(aes(x = decade, y = number_of_songs, 
               fill = charted), stat = "identity")  +
  theme(plot.title = element_text(hjust = 0.5),
        legend.title = element_blank(),
        panel.grid.minor = element_blank()) +
  ggtitle("Yayımlanan Şarkılar") +
  labs(x = NULL, y = "Şarkı Sayısı")

prince released songs by year chart

Bu, en üretken on yılının 1990’lar olduğunu açıkça gösteriyor.

Şimdi chart_level ile benzer bir grafik oluşturun.

Eğilimi görebilmek için hem decade hem chart_level ile group_by() yapmayı unutmayın.

Bu grafikte yalnızca listeye giren şarkılara bakacağınız için peak > 0 kullanarak diğer her şeyi filtreleyin. group_by nesnesini n() ile şarkı sayısını saymak üzere summarise()’a aktarın. Bunu bir değişkende saklarken, basit bir çubuk grafik için ggplot()’a da aktarabilirsiniz.

charted_songs_over_time <- prince %>%
  filter(peak > 0) %>%
  group_by(decade, chart_level) %>%
  summarise(number_of_songs = n())

charted_songs_over_time %>% 
  ggplot() + 
  geom_bar(aes(x = decade, y = number_of_songs, 
               fill = chart_level), stat = "identity") +
  theme(plot.title = element_text(hjust = 0.5),
        legend.title = element_blank(),
        panel.grid.minor = element_blank()) +
  labs(x = NULL, y = "Şarkı Sayısı") +
  ggtitle("Listeye Giren Şarkılar")

prince charted songs by year chart

İçgörüler

Prince’in listeye giren tüm şarkıları içinde çoğunluğun Top 10’a ulaştığına dikkat edin. Ama daha da ilginci, yeni şarkılar açısından en üretken on yılı 1990’lar olmasına rağmen, daha çok liste başarısı 1980’lerde yaşanmış. Neden? Metin madenciliği bölümlerini incelerken bu soruyu aklınızda tutun.

Şarkı sözü analizi için tam veri setinin gücünden yararlanmak üzere, liste seviyesi ve yayımlanma yılına dair referansları kaldırarak madencilik yapabileceğiniz çok daha büyük bir şarkı kümesine sahip olabilirsiniz. Bir bakın:

#look at the full data set at your disposal
prince %>%
  group_by(decade, chart_level) %>%
  summarise(number_of_songs = n()) %>%
  ggplot() +
  geom_bar(aes(x = decade, y = number_of_songs, 
               fill = chart_level), stat = "identity")  +
  theme(plot.title = element_text(hjust = 0.5),
        legend.title = element_blank(),
        panel.grid.minor = element_blank()) +
  labs(x = NULL, y = "Şarkı Sayısı") +
  ggtitle("Verideki Tüm Şarkılar")

all songs in data chart

Gördüğünüz gibi, veride yayımlanma tarihi olmayan yüzlerce Prince şarkısı var. Duygu analizi veya keşifsel analiz için tüm veriyi kullanabilirsiniz; ancak zaman içindeki eğilimler için çalışabileceğiniz çok daha küçük bir küme kalır. Bu sorun değil — yalnızca akılda tutulması gereken bir nokta.

1 Numaralı Şarkılar!

Sıkı Prince hayranları için, listelerde 1 Numara olan şarkılara hızlı bir bakış aşağıda. (knitr ve kableExtra paketlerinden kable() ve kable_styling() ile formattable’dan color_tile() kullanarak güzel biçimlendirilmiş HTML çıktı oluşturabileceğinizi unutmayın.)

library(knitr) # for dynamic reporting
library(kableExtra) # create a nicely formated HTML table
library(formattable) # for the color_tile function
prince %>%
  filter(peak == "1") %>%
  select(year, song, peak) %>%
  arrange(year) %>%
  mutate(year = color_tile("lightblue", "lightgreen")(year)) %>%
  mutate(peak = color_tile("lightgreen", "lightgreen")(peak)) %>%
  kable("html", escape = FALSE, align = "c", caption = "Prince's No. 1 Songs") %>%
  kable_styling(bootstrap_options = 
                  c("striped", "condensed", "bordered"), 
                  full_width = FALSE)
Prince's No. 1 Songs
yearsongpeak
1979i wanna be your lover1
1984erotic city1
1984purple rain1
1984when doves cry1
1985around the world in a day1
1986kiss1
1988lovesexy1
1989batdance1
1990thieves in the temple1
1991diamonds and pearls1
1995the most beautiful girl in the world1
200631211
2007planet earth1

Metin Madenciliği

Metin madenciliği, metin analitiği olarak da düşünülebilir. Amaç, muhtemelen bilinmeyen ya da bariz olanın altında gömülü kalmış ilgili bilgileri keşfetmektir. Doğal Dil İşleme (NLP), metin madenciliğinde kullanılan yöntemlerden biridir. Yazılı dildeki belirsizlikleri çözmek için tokenizasyon, kümeleme, varlık ve kelime ilişkilerini çıkarma ve temaları belirlemek ile öznel bilgileri nicelleştirmek için algoritmalar kullanır. Sözel karmaşıklık kavramını parçalayarak başlayacaksınız.

Sözel karmaşıklık farklı bağlamlarda farklı şeyler ifade edebilir; ancak şimdilik, şu ölçülerin birleşimiyle tanımlanabileceğini varsayalım:

  • Kelime Sıklığı: şarkı başına kelime sayısı
  • Kelime Uzunluğu: bir metindeki bireysel kelimelerin ortalama uzunluğu
  • Sözel Çeşitlilik: bir metinde kullanılan benzersiz kelimelerin sayısı (şarkı söz varlığı)
  • Sözel Yoğunluk: benzersiz kelime sayısının toplam kelime sayısına oranı (kelime tekrarı)

Tidy Metin Biçimi

Analize başlamak için, şarkı sözlerini tek tek kelimelere ayırmanız ve içgörü madenciliğine başlamanız gerekir. Bu işleme tokenizasyon denir.

Veri Biçimleri ve Tokenizasyon

Metin madenciliğinde kullanılabilecek farklı yöntemler ve veri biçimleri olduğunu unutmayın:

  • Korpus: tm metin madenciliği paketi tarafından oluşturulan belge koleksiyonları
  • Belge-terim matrisi: korpustaki tüm kelime oluşumlarını belge bazında listeleyen, belgelerin satırlar, kelimelerin sütunlar olduğu matris
  • Tidy Metin: satır başına bir token içeren bir tablo. Bu vaka çalışmasında bir token bir kelime (veya İkinci Bölüm’de ele alınacak bir n-gram) olacaktır. Tokenizasyon, bu nedenle şarkı sözlerini token’lara bölme işlemidir. Bu eğitimde tidytext’in unnest_tokens() işlevi kullanılacaktır. Daha fazla ayrıntı için tidytext belgelendirmesine bakın.

Ancak herhangi bir tokenizasyondan önce, veriyi temizlemede bir adım daha var. Birçok şarkı sözü, yazıya dökülürken "Repeat Chorus" gibi ifadeler veya "Bridge" ve "Verse" gibi etiketler içerir. Sonuçları bulanıklaştırabilecek başka istenmeyen kelimeler de çoktur. Ön analiz yaptıktan sonra, aradan çıkarmak istediğim birkaçını seçtim.

Aşağıda, elle kaldırılması gereken gereksiz kelimelerin bir listesi bulunuyor:

undesirable_words <- c("prince", "chorus", "repeat", "lyrics", 
                       "theres", "bridge", "fe0f", "yeah", "baby", 
                       "alright", "wanna", "gonna", "chorus", "verse", 
                       "whoa", "gotta", "make", "miscellaneous", "2", 
                       "4", "ooh", "uurh", "pheromone", "poompoom", "3121", 
                       "matic", " ai ", " ca ", " la ", "hey", " na ", 
                       " da ", " uh ", " tin ", "  ll", "transcription",
                       "repeats")

Token’ları açmak için, zaten yüklenmiş olan tidytext kütüphanesini kullanın. Artık dplyr’ın yeteneklerinden yararlanabilir ve birkaç adımı birleştirebilirsiniz.

Tidy metin çerçevesinden, hem metni tekil token’lara (tokenizasyon) bölmeniz hem de tidy bir veri yapısına dönüştürmeniz gerekir. Bunu yapmak için tidytext’in unnest_tokens() işlevini kullanın. unnest_tokens(), en az iki argüman gerektirir: metin çözülürken oluşturulacak çıktı sütununun adı (bu durumda "word") ve mevcut metni tutan girdi sütunu (ör. lyrics).

prince veri setini alıp unnest_tokens()’a aktarabilir ve ardından durdurma (stop) kelimelerini kaldırabilirsiniz. Stop kelimeler nelerdir? Çok iyi bildiğiniz, sonuçlarımıza anlam katmayabilecek kadar yaygın kelimelerdir. Seçilebilecek farklı listeler vardır; burada tidytext paketindeki stop_words sözlüğünü kullanacaksınız.

Bu stop kelimelerden rastgele bir liste göstermek için sample(), 15 kelimeyle sınırlamak için head() kullanın.

head(sample(stop_words$word, 15), 15)
 [1] "where"      "sensible"   "except"     "wouldn't"   "normally"   "relatively"
 [7] "has"        "said"       "yet"        "how"        "this"       "available" 
[13] "therein"    "different"  "followed"

Dolayısıyla, şarkı sözlerini kelimelere ayırdıktan sonra, dplyr’ın anti_join() işlevini kullanarak stop kelimeleri kaldırabilirsiniz. Ardından, önceden tanımlanan istenmeyen kelimelerden dplyr’ın filter() fiili ve %in% operatörü ile kurtulun. Sonra yinelenen kayıtları kaldırmak için distinct() kullanın. Son olarak, dört karakterden kısa tüm kelimeleri kaldırabilirsiniz. Bu da öznel bir karardır; ancak sözlerde bunlar çoğunlukla "yea ve hey" gibi ünlemlerdir. Sonuçları prince_words_filtered içine kaydedin.

Not: gelecekte başvurmak üzere, prince_words_filtered; 1) stop kelimeler, 2) istenmeyen kelimeler ve 3) 1-3 karakterli kelimeler olmadan prince veri çerçevesinin tidy metin sürümüdür. Bunu bazı analizlerde kullanacak, bazılarında kullanmayacaksınız.

#unnest and remove stop, undesirable and short words
prince_words_filtered <- prince %>%
  unnest_tokens(word, lyrics) %>%
  anti_join(stop_words) %>%
  distinct() %>%
  filter(!word %in% undesirable_words) %>%
  filter(nchar(word) > 3)

stop_words’un bir word sütunu olduğunu ve unnest_tokens() tarafından word adlı yeni bir sütun oluşturulduğunu fark edin; dolayısıyla anti_join() otomatik olarak word sütununda birleştirir.

Artık yeni tidy veri yapınızın sınıfını ve boyutlarını inceleyebilirsiniz:

class(prince_words_filtered)
[1] "data.frame"
dim(prince_words_filtered)
[1] 36916    10

prince_words_filtered, toplam 36916 kelime (benzersiz olmayan) ve 10 sütundan oluşan bir veri çerçevesidir. İşte bir anlık görüntü: (Sadece bir kelime seçip 10 şarkıdaki görünümlerini sınırladım ve ilgi çekici alanları sırayla yazdırmak için select() kullandım; yine biçimlendirme için knitr kullandım). Bu size token’lanmış, özetlenmemiş, tidy veri yapısını gösterir.

 prince_words_filtered %>% 
  filter(word == "race") %>%
  select(word, song, year, peak, decade, chart_level, charted) %>%
  arrange() %>%
  top_n(10,song) %>%
  mutate(song = color_tile("lightblue","lightblue")(song)) %>%
  mutate(word = color_tile("lightgreen","lightgreen")(word)) %>%
  kable("html", escape = FALSE, align = "c", caption = "Tokenized Format Example") %>%
  kable_styling(bootstrap_options = 
                  c("striped", "condensed", "bordered"), 
                  full_width = FALSE)
Tokenized Format Example
wordsongyearpeakdecadechart_levelcharted
racelovesexy198811980sTop 10Charted
racemy treeNANANAUnchartedUncharted
racepositivity1988NA1980sUnchartedUncharted
racerace1994NA1990sUnchartedUncharted
racesexuality1981881980sTop 100Charted
raceslow love1987NA1980sUnchartedUncharted
racethe rest of my life1999NA1990sUnchartedUncharted
racethe undertakerNANANAUnchartedUncharted
raceu make my sun shineNANANAUnchartedUncharted
racewelcome 2 the rat raceNANANAUnchartedUncharted

Her satırın, göründüğü her şarkı için yinelenecek tek bir kelime içerdiğini görebilirsiniz.

Kelime Sıklığı

Müzikte, tek tek kelime sıklıkları ister tekrar ister nadirlik olsun büyük önem taşır. Her ikisi de şarkının akılda kalıcılığını etkiler. Bir söz yazarı bilmek isteyebilir: kelime sıklığı ile hit şarkılar arasında bir ilişki var mı? Şimdi, tidy biçimi bir adım daha ileri götürüp şarkı başına kelime sayısının özetlenmiş dökümünü elde etmek istiyorsunuz.

Prince’in sözlerinde bu biçimi incelemek için, Billboard Listelerindeki konuma göre şarkı bazında gruplanmış kelime sayımı dağılımını gösteren bir histogram oluşturun. Gerçek bir kelime sıklığı sayımı elde etmek için prince sözlerini, hiçbir kelimeyi filtrelemeden tekrar unnest edin. Yine group_by() ve summarise() kullanarak sayımları alın. Ardından, dplyr’ın arrange() fiilini kullanarak sayıya göre sıralayın. Önce en yüksek sayılara bakın, sonra histogram için ggplot() kullanın.

full_word_count <- prince %>%
  unnest_tokens(word, lyrics) %>%
  group_by(song,chart_level) %>%
  summarise(num_words = n()) %>%
  arrange(desc(num_words)) 

full_word_count[1:10,] %>%
  ungroup(num_words, song) %>%
  mutate(num_words = color_bar("lightblue")(num_words)) %>%
  mutate(song = color_tile("lightpink","lightpink")(song)) %>%
  kable("html", escape = FALSE, align = "c", caption = "Songs With Highest Word Count") %>%
  kable_styling(bootstrap_options = 
                  c("striped", "condensed", "bordered"), 
                  full_width = FALSE)
Songs With Highest Word Count
songchart_levelnum_words
johnnyUncharted1349
cloreen bacon skinUncharted1263
push it upUncharted1240
the exodus has begunUncharted1072
wild and looseUncharted1031
jugheadUncharted940
my name is princeTop 10916
acknowledge meUncharted913
the walkUncharted883
the purple medleyUncharted874
full_word_count %>%
  ggplot() +
    geom_histogram(aes(x = num_words, fill = chart_level )) +
    ylab("Song Count") + 
    xlab("Word Count per Song") +
    ggtitle("Word Count Distribution") +
    theme(plot.title = element_text(hjust = 0.5),
          legend.title = element_blank(),
          panel.grid.minor.y = element_blank())

word count distribution chart

Sağa çarpık olduğuna dikkat edin. Şarkı sözü dökümünün doğası gereği, veri girişi hatalarından şüpheliyim. O yüzden, meraktan, 800’ün üzerinde kelimeye sahip o Top 10 şarkıya bir göz atın.

full_word_count %>%
  filter(chart_level == 'Top 10' & num_words > 800) %>%
  left_join(prince_orig, by = "song") %>%
  select(Song = song, 
         "Word Count" = num_words, 
         "Peak Position" = peak, 
         "US Pop" = US.Pop, 
         "US R&B" = US.R.B, 
         Canada = CA, 
         Ireland = IR) %>%
  kable("html", escape = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "condensed", "bordered"))
SongWord CountPeak PositionUS PopUS R&BCanadaIreland
my name is prince9165362555

Biraz araştırma yaptım ve bu şarkıda rap bölümü icra eden bir konuk sanatçı olduğunu keşfettim. Bu da durumu açıklıyor! Bu veri setinin dünya genelinde Pop ve R&B listelerini kapsadığını unutmayın; dolayısıyla tür ve coğrafya varsayımlarınızı büyük ölçüde etkileyebilir. Örneğin, Kanada’da 5’e kadar yükselmesine karşın, ABD Pop listesi sıralamasının çok daha düşük olduğuna dikkat edin. Aklınızda bulunsun.

Öneri: Müzik analizini kendi başınıza ele almak isterseniz, neredeyse 50.000 sanatçı için 50’den fazla özelliğe (ör. tempo, ses yüksekliği, dans edilebilirlik vb.) sahip The Million Song Dataset’e göz atabilirsiniz! Şarkı sözlerine müzikal özellikler eklemek oldukça kapsamlı bir analiz sağlar.

En Sık Kelimeler

Tam söz kümesinde en sık kullanılan kelimeleri basitçe değerlendirmek için, temizlenmiş ve filtrelenmiş veri setinizde count() ve top_n() kullanarak en üst n kelimeyi alabilirsiniz. Ardından, kelimeleri sayıya göre sıralamak için reorder() kullanın ve dplyr’ın mutate() fiiliyle sıralanmış değeri word’a yeniden atayın. Bu, ggplot()’un güzelce göstermesini sağlar.

prince_words_filtered %>%
  count(word, sort = TRUE) %>%
  top_n(10) %>%
  ungroup() %>%
  mutate(word = reorder(word, n)) %>%
  ggplot() +
    geom_col(aes(word, n), fill = my_colors[4]) +
    theme(legend.position = "none", 
          plot.title = element_text(hjust = 0.5),
          panel.grid.major = element_blank()) +
    xlab("") + 
    ylab("Şarkı Sayısı") +
    ggtitle("Prince Şarkı Sözlerinde En Sık Kullanılan Kelimeler") +
    coord_flip()

most frequently used words in prince lyrics

Çoğu popüler müzikte olduğu gibi, love (aşk) yaygın bir tema gibi görünüyor. Sadece bu en üst kelimelere bakarak pek fazla varsayımda bulunmazdım; ancak sanatçının bakış açısına dair kesinlikle bazı içgörüler elde edebilirsiniz, yalnız tüm resmi vermez. Daha derine inmeden önce kısa bir görsel eğlence molası verin.

Kelime Bulutları

Kelime bulutları birçok çevrede kötü bir üne sahiptir ve dikkatli olmazsanız uygun olmayan bağlamlarda kullanılabilirler. Ancak doğası gereği hepimiz çok görsel varlıklarız ve gerçek içgörünün elde edilebileceği durumlar vardır. Sandy McKee’nin bazı örneklerine buradan bakın. Yalnız biraz ihtiyat payı ile kullanın.

Şimdilik, bazı havalı şeyler için wordcloud2 adlı yeni bir pakete göz atın. Bu paket, html widget’ları oluşturan yaratıcı bir bulut koleksiyonu sunar. Hatta bir kelimenin üzerine gelerek metindeki sıklığını görebilirsiniz. (Bu paket rMarkdown’da yavaş render edebilir ve sıklıkla kullandığı tarayıcı konusunda seçicidir. Umarız geliştirmeler yapılır.)

prince_words_counts <- prince_words_filtered %>%
  count(word, sort = TRUE) 

wordcloud2(prince_words_counts[1:300, ], size = .5)

Daha da eğlenceli olması için biraz veri sanatı ekleyebilirsiniz…

wordcloud2(prince_words_counts[1:300, ], figPath = "guitar_icon.png", 
           color = "random-dark", size = 1.5)

letterCloud(prince_words_counts[1:300, ], word = "PRINCE", size = 2)

kelime bulutu 1

kelime bulutu 2

Şimdiye dek yalnızca tüm şarkılar boyunca en üst kelimeleri gördünüz. Peki bunları liste seviyesine göre ayırırsanız ne olur? Listelere giren şarkılarda bazı kelimeler, listeye girmeyen şarkılara göre daha mı yaygın? Bunlar toplum tarafından popüler görülen kelimelerdir.

Aşağıdaki kodda, her chart_level için ilk n kelimeyi almak üzere slice(seq_len(n)) kullanımına dikkat edin. Bu, top_n()’dan farklı çalışır ve grafiğinizde fasetleme kullanırken iyi bir seçimdir. (Böyle numaralar için her zaman farklı yollar olduğunu unutmayın.) Ayrıca, grafikte kelimeleri doğru sırada listeleyebilmek için row_number() işlevini kullanabilirsiniz. ggplot() varsayılan olarak kelimeleri alfabetik sıralar; grafikten önce sıralama yapmak iyi bir pratiktir.

popular_words <- prince_words_filtered %>% 
  group_by(chart_level) %>%
  count(word, chart_level, sort = TRUE) %>%
  slice(seq_len(8)) %>%
  ungroup() %>%
  arrange(chart_level,n) %>%
  mutate(row = row_number()) 

popular_words %>%
  ggplot(aes(row, n, fill = chart_level)) +
    geom_col(show.legend = NULL) +
    labs(x = NULL, y = "Şarkı Sayısı") +
    ggtitle("Liste Seviyesine Göre Popüler Kelimeler") + 
    theme_lyrics() +  
    facet_wrap(~chart_level, scales = "free") +
    scale_x_continuous(  # This handles replacement of row 
      breaks = popular_words$row, # notice need to reuse data frame
      labels = popular_words$word) +
    coord_flip()

popular words by chart level

Buradan ne tür içgörüler çıkarıyorsunuz?

Görüldüğü gibi, liste seviyeleri genelinde en üst kelimeler birbirine çok, ama çok benziyor. Bu, bir şarkının başarısını yalnızca sözlere bakarak tahmin etme umutlarımız için pek iyi görünmüyor! Ancak metin madenciliğiyle mümkün olanların yalnızca yüzeyine dokundunuz ve sonunda NLP ile öngörücü modellemeye geçeceksiniz.

Zamansız Kelimeler

Müzikte bazı kelimeler zamansız kabul edilir. Zamansız kelimeler zaman içinde kalıcılığını korur ve geniş bir kitleye hitap eder. Analizinizi on yıllara göre bölerseniz, bu kelimeler zirveye çıkar. Prince’in sözlerinden her on yıl için en üst kelimeleri almak ve hangi kelimelerin zamansız ya da trend olduğunu görmek için filtreleme, gruplama ve toplulaştırmayı kullanın. On yıla göre görüntülemek için facet_wrap() ile ggplot() kullanabilirsiniz.

timeless_words <- prince_words_filtered %>% 
  filter(decade != 'NA') %>%
  group_by(decade) %>%
  count(word, decade, sort = TRUE) %>%
  slice(seq_len(8)) %>%
  ungroup() %>%
  arrange(decade,n) %>%
  mutate(row = row_number()) 

timeless_words %>%
  ggplot(aes(row, n, fill = decade)) +
    geom_col(show.legend = NULL) +
    labs(x = NULL, y = "Şarkı Sayısı") +
    ggtitle("Zamansız Kelimeler") + 
    theme_lyrics() +  
    facet_wrap(~decade, scales = "free", ncol = 5) +
    scale_x_continuous(  # This handles replacement of row 
      breaks = timeless_words$row, # notice need to reuse data frame
      labels = timeless_words$word) +
    coord_flip()

timeless words

Açıkça görülüyor ki love, time ve girl zamansız. Peki trend olan kelimeleri saptamak ne kadar kolay? truth milenyumun başında trend miydi? Belki de yalnızca bazı şarkılarda çok tekrarlanan bir kelimedir? Sıklık gerçekten temaları tanımlar mı? Bu, Birliğin Durumu konuşmalarını analiz etmek gibi diğer metin madenciliği görevlerinde olduğu gibi şarkı sözlerinde de işe yarar mı?

Kelime Uzunluğu

Kelime uzunluğu, söz yazarları için ilginç bir konudur. Kelime ne kadar uzunsa, kafiyelendirmek ve bir kalıba sığdırmak o kadar zordur. Aşağıda gösterilen kelime uzunlukları histogramı beklendiği gibidir; birkaç inanılmaz uzun istisna ile.

#unnest and remove undesirable words, but leave in stop and short words
prince_word_lengths <- prince %>%
  unnest_tokens(word, lyrics) %>%
  group_by(song,decade) %>%
  distinct() %>%
  filter(!word %in% undesirable_words) %>%
  mutate(word_length = nchar(word)) 

prince_word_lengths %>%
  count(word_length, sort = TRUE) %>%
  ggplot(aes(word_length), 
         binwidth = 10) + 
    geom_histogram(aes(fill = ..count..),
                   breaks = seq(1,25, by = 2), 
                   show.legend = FALSE) + 
    xlab("Kelime Uzunluğu") + 
    ylab("Kelime Sayısı") +
    ggtitle("Kelime Uzunluğu Dağılımı") +
    theme(plot.title = element_text(hjust = 0.5),
          panel.grid.minor = element_blank())

word length distribution

Bu çılgınca uzun kelimeler neler? Tamamen eğlencelik bir kelime bulutu zamanı! Bu, kelime sıklığı yerine kelime uzunluğuna dayanır. Göz atın:

wc <- prince_word_lengths %>%
  ungroup() %>%
  select(word, word_length) %>%
  distinct() %>%
  arrange(desc(word_length))

wordcloud2(wc[1:300, ], 
           size = .15,
           minSize = .0005,
           ellipticity = .3, 
           rotateRatio = 1, 
           fontWeight = "bold")

Sözel Çeşitlilik

Bir metnin söz varlığı ne kadar çeşitliyse, sözel çeşitliliği (lexical diversity) o kadar yüksektir. Şarkı Söz Varlığı, bir şarkıda kullanılan benzersiz kelime sayısının bir temsilidir. Bu, yıllara göre şarkı başına ortalama benzersiz kelimelerin basit bir grafiğiyle gösterilebilir. Bu grafikte niceliksel içgörülere daha çok baktığınız için, orijinal veri setini yeniden token’layacak ancak tüm stop ve kısa kelimeleri tutacaksınız.

lex_diversity_per_year <- prince %>%
  filter(decade != "NA") %>%
  unnest_tokens(word, lyrics) %>%
  group_by(song,year) %>%
  summarise(lex_diversity = n_distinct(word)) %>%
  arrange(desc(lex_diversity)) 

diversity_plot <- lex_diversity_per_year %>%
  ggplot(aes(year, lex_diversity)) +
    geom_point(color = my_colors[3],
               alpha = .4, 
               size = 4, 
               position = "jitter") + 
    stat_smooth(color = "black", se = FALSE, method = "lm") +
    geom_smooth(aes(x = year, y = lex_diversity), se = FALSE,
                color = "blue", lwd = 2) +
    ggtitle("Sözel Çeşitlilik") +
    xlab("") + 
    ylab("") +
    scale_color_manual(values = my_colors) +
    theme_classic() + 
    theme_lyrics()

diversity_plot

lexical diversity

Bu ne anlama geliyor? Son birkaç on yılda Prince’in söz çeşitliliğinde hafif bir yukarı yönlü eğilim vardı. Bu, liste başarısıyla nasıl ilişkilidir? Gerçekten söylemesi zor; ama karşılaştırma için yoğunluk ve liste geçmişini de çizelim.

Sözel Yoğunluk

Bu eğitim için sözel yoğunluğun, benzersiz kelime sayısının toplam kelime sayısına oranı olarak tanımlandığını hatırlayın. Bu, kelime tekrarının bir göstergesidir; bu da bir söz yazarının kritik bir aracıdır. Sözel yoğunluk arttıkça, tekrar azalır. (Not: bu, bir başka söz yazarlığı numarası olan ardışık tekrarı ima etmez.)

Prince’in yıllara göre sözel yoğunluğuna bir bakın. Yoğunluk için, stop kelimeler de dahil tüm kelimeleri tutmak en iyisidir. Bu nedenle, orijinal veri setiyle başlayıp kelimeleri unnest edin. Şarkı ve yıla göre gruplayın ve yoğunluğu hesaplamak için n_distinct() ve n() kullanın. Bunu geom_smooth() ile ggplot()’a aktarın. Doğrusal bir yumuşatma modeli için method="lm" ile ek bir stat_smooth() ekleyin.

lex_density_per_year <- prince %>%
  filter(decade != "NA") %>%
  unnest_tokens(word, lyrics) %>%
  group_by(song,year) %>%
  summarise(lex_density = n_distinct(word)/n()) %>%
  arrange(desc(lex_density))

density_plot <- lex_density_per_year %>%
  ggplot(aes(year, lex_density)) + 
    geom_point(color = my_colors[4],
               alpha = .4, 
               size = 4, 
               position = "jitter") + 
    stat_smooth(color = "black", 
                se = FALSE, 
                method = "lm") +
    geom_smooth(aes(x = year, y = lex_density), 
                se = FALSE,
                color = "blue", 
                lwd = 2) +
    ggtitle("Sözel Yoğunluk") + 
    xlab("") + 
    ylab("") +
    scale_color_manual(values = my_colors) +
    theme_classic() + 
    theme_lyrics()

density_plot

lexical density

Eğilimleri karşılaştırmak için, liste geçmişi (yani listelere giren başarılı şarkılar) için bir grafik oluşturun ve bunu çeşitlilik ve yoğunlukla kıyaslayın. gridExtra’dan grid.arrange() kullanarak yan yana çizin.

chart_history <- prince %>%
  filter(peak > 0) %>%
  group_by(year, chart_level) %>%
  summarise(number_of_songs = n()) %>%
  ggplot(aes(year, number_of_songs)) + 
    geom_point(color = my_colors[5],
               alpha = .4, 
               size = 4, 
               position = "jitter") +
    geom_smooth(aes(x = year, y = number_of_songs), 
                se = FALSE, 
                method = "lm", 
                color = "black" ) +
    geom_smooth(aes(x = year, y = number_of_songs), 
                se = FALSE,
                color = "blue", 
                lwd = 2) +
   ggtitle("Liste Geçmişi") +
   xlab("") + 
   ylab("") +
   scale_color_manual(values = my_colors) +
   theme_classic() + 
   theme_lyrics()

grid.arrange(diversity_plot, density_plot, chart_history, ncol = 3)

lexical diversity x lexical density x chart history

Yukarıdan, Prince’in sözel çeşitliliği ve yoğunluğunda yıllar içinde hafif bir artış olduğunu görüyorsunuz. Bu eğilim, tüm popüler müzikle nasıl karşılaştırılır? Bir çalışma, Hit Şarkılarda sözel yoğunluğun azaldığını, bunun da tekrarın arttığını (yani "daha az şey söyleyen daha çok kelime") gösterdiğini ortaya koyuyor. Prince’in şarkılarında olan bu değil. Bir diğer çalışma ise tüm popüler müzik genelinde çeşitliliğin (benzersiz kelimeler) zamanla arttığını ve bunun Prince’in müziğiyle olumlu yönde ilişkili olduğunu ortaya koyuyor. Bu, tarih boyunca liste sıralamalarında tür çeşitliliğinin artmasıyla ilişkili olabilir. Tür, bu veri setinde bulunmayan kritik bir veri parçası. Popüler müzik için liste geçmişi düşerken R&B/Rap için artıyor olabilir mi?

Öneri: Bu sonuçları düşünmenizi ve hatta bu becerileri kendi başınıza kullanabileceğiniz farklı veri setleri aramanızı teşvik ediyorum! Unutmayın, korelasyon nedenselliği ima etmez.

TF-IDF

Şimdiye kadar kullandığınız yöntem, tüm veri setine baktı; ancak bir bütün içinde çeşitli terimlerin bir belge için ne kadar önemli olduğunu sayısallaştırmayı ele almadı. Terim sıklığına baktınız ve stop kelimeleri kaldırdınız; ama bu en sofistike yaklaşım olmayabilir.

Karşınızda TF-IDF. TF "terim sıklığıdır" (term frequency). IDF ise "ters belge sıklığıdır" (inverse document frequency) ve yaygın kullanılan kelimelere daha düşük, koleksiyonda az kullanılan kelimelere daha yüksek ağırlık verir. TF ve IDF’yi birleştirdiğinizde, bir terimin önemi, ne kadar nadir kullanıldığına göre ayarlanır. TF-IDF’nin ardındaki varsayım, bir belgede daha sık görünen terimlerin daha yüksek ağırlık alması gerektiğidir; ta ki pek çok belgede de görünmüyorsa. Formül özetle şöyle verilebilir:

  • Terim Sıklığı (TF): Bir belgede bir terimin geçme sayısı
  • Belge Sıklığı (DF): Her kelimeyi içeren belge sayısı
  • Ters Belge Sıklığı (IDF) = 1/DF
  • TF-IDF = TF * IDF

Dolayısıyla, bir koleksiyondaki belgelerin daha azında görülen kelimeler için herhangi bir terimin IDF’si daha yüksek bir sayıdır. tidytext’in sağladığı bind_tf_idf() işleviyle, liste seviyesi başına en önemli kelimeleri incelemek için bu yeni yaklaşımı kullanabilirsiniz. Bu işlev, TF ve IDF’yi hesaplar ve TF*IDF çarpımıyla birlikte bağlar. Girdi olarak, belge (şarkı) başına token (kelime) başına bir satır içeren tidy bir metin veri seti alır. Sonuçları yeni sütunlarda göreceksiniz.

Öyleyse, orijinal Prince veri çerçevenizi alın ve token’ları kelimelere açın, istenmeyen kelimeleri kaldırın; ancak stop kelimeleri tutun. Sonra bind_tf_idf() kullanarak formülleri çalıştırın ve yeni sütunlar oluşturun.

 popular_tfidf_words <- prince %>
  unnest_tokens(word, lyrics) %>%
  distinct() %>%
  filter(!word %in% undesirable_words) %>%
  filter(nchar(word) > 3) %>%
  count(chart_level, word, sort = TRUE) %>%
  ungroup() %>%
  bind_tf_idf(word, chart_level, n)

head(popular_tfidf_words)
## # A tibble: 6 x 6
##   chart_level  word     n          tf   idf tf_idf
##         <chr> <chr> <int>       <dbl> <dbl>  <dbl>
## 1   Uncharted  that   622 0.010942420     0      0
## 2   Uncharted  your   529 0.009306335     0      0
## 3   Uncharted  what   496 0.008725789     0      0
## 4   Uncharted  will   481 0.008461904     0      0
## 5   Uncharted  this   464 0.008162834     0      0
## 6   Uncharted  know   441 0.007758211     0      0

Şimdi, çok yaygın kelimeler için IDF ve TF-IDF’nin 0 olduğunu görebilirsiniz. (Teknik olarak, IDF terimi doğal logaritmada 1 olur ve bu nedenle bu kelimeler için sıfırdır.) Yukarıdaki sonuçlarınızı arrange() içine aktarın ve tf-idf’ye göre azalan şekilde sıralayın. Birkaç adım daha ekleyin ve Prince’in sözlerindeki kelimelere bakmanın farklı bir yolunu göreceksiniz.

top_popular_tfidf_words <- popular_tfidf_words %>%
  arrange(desc(tf_idf)) %>%
  mutate(word = factor(word, levels = rev(unique(word)))) %>%
  group_by(chart_level) %> 
  slice(seq_len(8)) %>%
  ungroup() %>%
  arrange(chart_level, tf_idf) %>%
  mutate(row = row_number())

top_popular_tfidf_words %>%
  ggplot(aes(x = row, tf_idf, 
             fill = chart_level)) +
    geom_col(show.legend = NULL) +
    labs(x = NULL, y = "TF-IDF") + 
    ggtitle("Liste Seviyesine Göre TF-IDF ile Önemli Kelimeler") +
    theme_lyrics() +  
    facet_wrap(~chart_level, ncol = 3, scales = "free") +
    scale_x_continuous(  # This handles replacement of row 
      breaks = top_popular_tfidf_words$row, # notice need to reuse data frame
      labels = top_popular_tfidf_words$word) +
    coord_flip()

tf-idf

Vay canına, TF-IDF kullanmak potansiyel olarak önemli kelimelere bambaşka bir bakış açısı sunuyor. Elbette yorum tamamen öznel. Herhangi bir desen fark ettiniz mi?

Şimdi de TF-IDF’ye zamana göre bakın:

tfidf_words_decade <- prince %>%
  unnest_tokens(word, lyrics) %>%
  distinct() %>%
  filter(!word %in% undesirable_words & decade != 'NA') %>%
  filter(nchar(word) > 3) %>%
  count(decade, word, sort = TRUE) %>%
  ungroup() %>%
  bind_tf_idf(word, decade, n) %>%
  arrange(desc(tf_idf))

top_tfidf_words_decade <- tfidf_words_decade %>% 
  group_by(decade) %>% 
  slice(seq_len(8)) %>%
  ungroup() %>%
  arrange(decade, tf_idf) %>%
  mutate(row = row_number())

top_tfidf_words_decade %>%
  ggplot(aes(x = row, tf_idf, fill = decade)) +
    geom_col(show.legend = NULL) +
    labs(x = NULL, y = "TF-IDF") + 
    ggtitle("On Yıla Göre TF-IDF ile Önemli Kelimeler") +
    theme_lyrics() +  
    facet_wrap(~decade, 
               ncol = 3, nrow = 2, 
               scales = "free") +
    scale_x_continuous(  # this handles replacement of row 
      breaks = top_tfidf_words_decade$row, # notice need to reuse data frame
      labels = top_tfidf_words_decade$word) +
    coord_flip()

tf-idf 2

Şimdi kesinlikle daha derin bir içgörü düzeyi elde ediyorsunuz. Zamansız kelimeler artık baskın değil. Konular veya temalar belirmeye başladı mı? Gerçekten yalnızca grup başına birkaç kelimeyle mümkün mü? Bunu ikinci eğitimde (İkinci Bölüm: NLP ile Duygu Analizi ve Konu Modellemesi) yeni boyutlara taşıyacaksınız.

Bu yöntemle hızlı bir kelime bulutu, Prince’in sözlerindeki önemli kelimelere yeni bir bakış sunar ve biraz daha ilgi çekicidir…

wc <- tfidf_words_decade %>%
  arrange(desc(tf_idf)) %>%
  select(word, tf_idf)

wordcloud2(wc[1:300, ], 
           color = "random-dark", 
           minRotation = -pi / 6, 
           maxRotation = -pi / 3, 
           minSize = .002, 
           ellipticity = .3, 
           rotateRatio = 1, 
           size = .2, 
           fontWeight = "bold", 
           gridSize = 1.5 )

Sonuç

Bu vaka çalışmasında önce, yalnızca temel unsurlara bakarak gerçek veriye bir göz attınız. Veri temizleme ve bilgilendirici olmayan kelimeleri kaldırma gibi bazı koşullandırmalar yaptıktan sonra, şarkı düzeyinde keşifsel bir analize başladınız.

Ardından, sözleri token’lanmış kelimelere ayırarak sözel karmaşıklığa bakabilmek için metin madenciliğine daha derinlemesine girdiniz. Sonuçlar, bir sonraki adımlar olan duygu analizi ve konu modellemesi için kritik içgörüler sağlar.

Son olarak, bir belgede bir kelimenin, ilgi duyulan bir sonuçla ilişkili bilgisini temsil etmek için TF-IDF analizini kullandınız. Bunun müzikte temaları belirlemenin iyi bir yolu olduğunu düşünebilirsiniz; ama hikâyenin yalnızca yarısına sahipsiniz. İkinci Bölüm, Gizli Dirichlet Ayrımı (LDA) adlı gözetimsiz bir öğrenme yöntemini ele alır. Veri Bilimi’nin her alanında olduğu gibi, içgörü kazanmak için seçebileceğiniz pek çok yöntem vardır. Bu vaka çalışmasının İkinci ve Üçüncü Bölümlerinde bu seçeneklerden daha fazlasını ele alacaksınız.

Umarım, keşifsel analizden duygu analizine, konu modellemesine ve öngörücü içgörülere uzanan bu yolculuğa benim kadar siz de heyecanlısınızdır.

Okuduğunuz için teşekkürler; bir sonraki eğitimde görüşmek üzere!

Konular

İlgili