Lubimy czytać - coś o książkach

Jakiś czas temu była analiza ocen filmów (na podstawie bazy Filmwebu), obiecałem w różnych miejscach, że będzie też o książkach. Zatem sprawdźmy czego możemy się dowiedzieć z danych pobranych z serwisu LubimyCzytać.pl. Przez kilka tygodni skrypt działający sobie grzecznie na serwerze pobierał stronę po stronie z serwisu, analizował zapisane na niej dane i przepisywał je sobie do lokalnego pliku (dane zgromadziłem w pliku books_total.RDS, z którego za chwilę je wczytamy). I tutaj ciekawostka. Poprosiłem redakcję serwisu o przesłane danych, tak aby nie zapychać im serwerów. Poprosiłem jednocześnie zaznaczając, że chcę przygotować niniejszą analizę, a jeśli nie otrzymam danych - pobiorę je samodzielnie. Odmówiono mi. Żeby być miłym oszczędziłem serwery (swoje i cudze) i przed kolejnymi hitami w stronę czekałem losową liczbę sekund (od 1 do 3). Warto to robić, warto być przyzwoitym. Ale mimo wszystko nie udało się pobrać wszystkich danych (a ileż możecie czekać na nowy post?). Tak czy inaczej - mamy ponad 330 tysięcy wierszy. Wiersze zawierają informację o tytule książki, jej autora, wydawnictwo, datę wydania (skorzystamy tylko z roku), liczbie stron i kategorii do której dana książka została przypisana w serwisie. Dodatkowo - to co najbardziej ciekawe - mamy średnią ocenę, liczbę ocen oraz liczbę każdej z ocen przyznanych przez użytkownika (od 1 do 10 gwiazdek). Gdzieś jest też znacznik w jakim języku jest książka. Fajne dane, można sobie porobić różne przekroje. I tak zrobimy. Zaczynamy oczywiście od przygotowania środowiska - wczytanie pakietów i danych:

library(tidyverse)
library(tidytext)
library(wordcloud)

books <- readRDS("books_total.RDS")

theme_set(theme_minimal())

Od razu przystąpimy do analizy. Średnia ocena książki to 6.78 przy średniej liczbie ocen 65. A jak to wygląda według kategorii?

Średnia ocena książki według kategorii

books %>%
   # tylko książki z ocenami
   filter(!is.na(score_mean)) %>%
   # średnie oceny i liczby książek w ramach kategorii
   # oraz liczba książek w kategorii 
   group_by(category) %>%
   summarise(mean_score = mean(score_mean),
             mean_score_sum = round(mean(score_sum)),
             n=n()) %>%
   ungroup() %>%
   # weźmy tylko kategorie w których liczba książek jest powyżej mediany tej liczby
   filter(n > median(n)) %>%
   # kolejność słupków
   arrange(mean_score) %>%
   mutate(category = factor(category, levels=category)) %>%
   # wykres
   ggplot() +
      geom_bar(aes(category, mean_score), stat="identity",
               fill="lightgreen", color="darkgreen") +
      geom_text(aes(category, mean_score, label=paste0("(", n, ", ", mean_score_sum, ")")),
                hjust=-0.3) +
      geom_text(aes(category, mean_score, label=round(mean_score, 2)), hjust=1.3) +
      ylim(0,10) +
      coord_flip() +
      labs(x="Kategoria", y="Średnia ocena (liczba tytułów, średnia liczba ocen)")

Może trochę zaskakujące? Najlepiej oceniane są książki w kategoriach album, sztuka, komiks (z tych “obrazkowych”) oraz religia i poezja. Najgorsze według użytkowników LubimyCzytać są książki z kategorii literatura obyczajowa i romans (wiecie, że to tzw. harlequiny, prawda?). W środku stawki, powyżej średniej oceny (6.78) mamy większość kategorii. Ważne jest jeszcze jedno - żeby uznać średnią ocenę jako dość obiektywną powinna być zebrana z odpowiednio dużej próby. O wielkości tej próby będzie za chwilę, ale już teraz można powiedzieć, że niektóre kategorie mają za mało ocen. Takie mapy i atlasy na przykład, wspomniana sztuka czy już ewidentnie czasopisma. Skąd zaskoczenie? Sądziłem, że to co bardziej poczytne (druga liczba w nawiasie - kategorie najpopularniejsze to: klasyka, literatura młodzieżowa, thriller/kryminał, przygodowa, fantastyka i sci-fi, literatura współczesna i piękna) będzie miało większe oceny. Ale przecież z drugiej strony - wcale najpopularniejsze nie oznacza najlepsze, wręcz może być odwrotnie (w imię eat shit, miliony much nie mogą się mylić). Zobaczymy to za chwilę.

20 najpopularniejszych książek razem z ocenami

books %>%
   top_n(20, wt = score_sum) %>%
   mutate(auth_title = paste0(author, " \"", title, "\"")) %>%
   select(auth_title, score_sum, score_mean) %>%
   distinct() %>%
   arrange(score_sum) %>%
   mutate(auth_title=factor(auth_title, levels=unique(auth_title))) %>%
   ggplot() +
   geom_bar(aes(auth_title, score_mean), stat="identity", fill="lightgreen", color="darkgreen") +
   geom_text(aes(auth_title, score_mean, label=paste0("(", score_sum, ")")), hjust=-0.2) +
   geom_text(aes(auth_title, score_mean, label=round(score_mean, 2)), hjust=1.2) +
   ylim(0,10) +
   coord_flip() +
   labs(x="Autor i tytuł książki", y="Średnia ocena (liczba głosów)")

Wykres jest ułożony przewrotnie - na górze mamy te tytuły, które mają najwięcej ocen, a długość słupka odpowiada ocenie. Moja ulubiona książka Masłowskiej to bardzo dobry przykład na (uwaga, popularne słowo) hejt w internecie. Mam wrażenie, że sporo z tych ocen to jedynki, a mało jest tych ciągnących w górę… Można by zobaczyć to bezpośrednio w danych, ale problem jest taki (i dotyczy on większości tytułów), że w bazie LubimyCzytać powtarza się bardzo dużo książek. Bo wydane są w różnych wydawnictwach, bo są wznowienia (wydania w kolejnych latach), bo chyba coś nie tak jest w bazie danych. Taka właśnie “Wojna polsko-ruska pod flagą biało-czerwoną” występuje kilka razy (linki do stron dotyczącej tej książki poniżej) i wpisy wiele się nie różnią:

nStronaOcenaLiczba ocen
1Wydawnictwo: Lampa i Iskra Boża, rok: 20025.1852937
2Wydawnictwo: Lampa i Iskra Boża, rok: 20035.1842950
3Wydawnictwo: Świat Książki, rok: 20035.1852937
4Wydawnictwo: Lampa i Iskra Boża, rok: 20055.1842938
5Wydawnictwo: Code Red Tomasz Stachewicz, rok: 20155.1842938
6Wydawnictwo: Lampa i Iskra Boża5.1852937
7Wydawnictwo: Aleksandria5.1852937
8Wydawnictwo: Lampa i Iskra Boża5.4254615

Zobaczmy więc jaka jest średnia liczba poszczególnych ocen (liczba gwiazdek) dla tej konkretnej książki:

books %>%
   # tylko konkretna książka
   filter(title == "Wojna polsko-ruska pod flagą biało-czerwoną") %>%
   # tylko potrzebne kolumny
   select(score_1:score_10) %>%
   # unpivot
   gather() %>%
   # średnia liczba głosów według oceny
   group_by(key) %>%
   summarise(value = mean(value)) %>%
   ungroup() %>%
   # wysokość słupka jako procent
   mutate(proc = round(100 * value/sum(value), 1)) %>%
   # kolejność słupków
   mutate(key = factor(key, levels = c(paste0("score_", 1:10)))) %>%
   # wykres
   ggplot() +
   geom_bar(aes(key, value), stat="identity", fill="lightgreen", color="black") +
   geom_text(aes(key, value, label=paste0(proc, "%")), vjust = 1.3) +
   labs(x="Ocena", y="Liczba ocen")

Tak jak można było podejrzewać - dużo jedynek i trójek (łącznie to 1/4 ocen), bardzo mało 10. Najwięcej szóstek i siódemek (1/3 ocen) co się zgadza z ogółem (o tym będzie za moment). Wracając do najpopularniejszych książek - nie znam większości z tych tytułów, po tytułach wnioskuję że to czytadła pokroku “Sagi Zmierzch” dla młodzieży. Stosunkowo mało tutaj Paulo Coelho, znowu widać powtórki w tytułach, raz “Niezgodna” jest z autorem, innym razem bez, “Akademia wampirów” dwa razy… Oj, kiepska jakość bazy, kiepska. A Coelho jest ze średnią oceną 6.43 i średnią liczbą ocen 301. Z wykresu widać też, że “Brida” to jego najpopularniejsza książka.

Liczba ocen a ocena

Czy liczba ocen ma znaczenie? Pytanie (nie bezpośrednio) padło wyżej, poszukajmy odpowiedzi:

books %>%
   filter(!is.na(score_mean)) %>%
   ggplot() +
   geom_point(aes(score_sum, score_mean), color="lightgreen", alpha=0.2) +
   geom_smooth(aes(score_sum, score_mean), se = FALSE, color="darkred", size=2) +
   labs(x="Liczba głosów", y="Średnia ocena")

Liczba głosów nie ma znaczenia dla średniej oceny książki. Książki albo są dobre, albo złe - to czy swój głos odda 10 czy 1000 osób nie ma większego znaczenia. Poza tym, że średnia będzie coraz bliższa rzeczywistej obiektywnej oceny. Weryfikowałem to w przypadku filmów - co 30 minut pobierałem średnią ocenę i liczbę oddanych głosów filmu, który miał premierę (zaczynał więc bez żadnej oceny). Gdzieś w okolicach 100-200 oddanych głosów średnia się ustabilizowała. Można więc przyjąć, że jeśli na daną pozycję zagłosowało 100 lub więcej osób to ocena jest wiarygodna i nie będzie się zmieniać w czasie. Oczywiście wahnięcia o ułamek punktu są możliwe. To jest między innymi przyczyna, dla której wszelakie listy Top500 na IMBd.com lub innym FilmWebie są dość stabilne. To wynika też ze statystyki i liczności próby badawczej. Dlaczego badania przeprowadza się na reprezentatywnej próbie tysiąca Polaków? Dlatego, że tyle osób wystarczy do określenia jakie preferencje ma prawie 40 milionów. Serwisy internetowe mają mniejszą bazę użytkowników, w związku z tym liczebność próby badawczej (owe 100 ocen) jest mniejsza.

Średnia według wydawnictwa

books %>%
   # tylko to co ma ocenę i wydawcę
   filter(!is.na(score_mean), !is.na(publisher)) %>%
   # średnia ocena w ramach wydawnictwa
   group_by(publisher) %>%
   summarise(mean_score = mean(score_mean), n=n()) %>%
   ungroup() %>%
   # top 20 średnich ocen
   top_n(20, wt = n) %>%
   arrange(mean_score) %>%
   mutate(publisher = factor(publisher, levels=unique(publisher))) %>%
   # wykres
   ggplot() +
   geom_bar(aes(publisher, mean_score), stat="identity",
            fill="lightgreen", color="darkgreen") +
   geom_text(aes(publisher, mean_score, label=n), hjust=-0.2) +
   geom_text(aes(publisher, mean_score, label=round(mean_score, 2)), hjust=1.2) +
   ylim(0,10) +
   coord_flip() +
   labs(x="Wydawnictwo", y="Średnia ocena (liczba książek)")

Największe wydawnictwa wydają najlepsze tytuły. Po prostu. Pozycja druga to błąd w danych (lub ich scrappingu). Widzicie Harlequina na dole wykresu? Pamiętacie kategorię literatura obyczajowa i romans? Łączy się to jakoś? Nie widać tego bezpośrednio, można to jednak udowodnić odpowiednio zestawiając dane. Przejdźmy jednak dalej.

Rozkład liczby stron

Jak grube są książki?

books %>%
   # tylko to co ma liczbę stron :)
   filter(!is.na(pages)) %>%
   # to co ma tą liczbę poniżej 99-percentyla
   # to odcięcie wartości mocno odstających
   filter(pages <= quantile(pages, 0.99)) %>%
   ggplot() +
   geom_density(aes(pages), fill="lightgreen", color="black") +
   labs(x="Liczba stron", y="Gęstość prawdopodobieństwa")

Najwięcej jest książek około 180-230 stronicowych.

Rozkład liczby ocen

Najwięcej jest książek mających po kilka-kilkanaście ocen. Średnia liczba ocen to 65, obetnijmy więc powyższy wykres tylko do książek, które mają więcej ocen niż ich średnia: Jak widać - niewiele się zmienia, a najwięcej jest książek po około 100 ocen. Napisałem coś wyżej o stabilizacji średniej przy około 100 głosach albo o liczebności próby badawczej? Właśnie.

Rozkład ocen

Zobaczmy teraz jaka średnia ocena jest najbardziej popularna. Ale już uwzględniając te książki, które mają co najmniej 65 ocen (żeby wykluczyć książki ocenione na 10 przez jedną osobę). Średnio książka ma zatem ocenę bliską 7 (dokładnie 6.958) oraz medianę (połowa książek jest oceniona lepiej, a połowa gorzej) równą 6.979. Różnica pomiędzy średnią i medianą prawie żadna, a to widać już po wykresie gęstości prawdopodobieństwa - mamy tutaj rozkład taki trochę kopnięty normalny. Jak wygląda rozkład głosów? Czyli jakie oceny przyznają użytkownicy?

Rozkład nadawanych głosów

Najbardziej popularną oceną jest siódemka, następna w kolejności to szóstka (i to oczywiście powoduje średnią pomiędzy 6 a 7 - pamiętacie jeszcze oceny książki Masłowskiej?). To ciekawe spostrzeżenie, można je zauważyć w innych serwisach oceniających, na przykład filmy (sprawdź pierwszy wykres słupkowy w tekście o ocenach filmów). Może to być również przyczynek do upraszczania systemu gwiazdek - zamiast skali 10 stopniowej powinna wystarczyć na przykład trzystopniowa: zły, średni, dobry? Albo dwustopniowa: lubię lub nie lubię. Przy filmach pokusiłem się nawet o wyliczenie czegoś na kształt wskaźnika NPS.

Rozkład ocen według kategorii

Jak wyglądają oceny w ramach kategorii? Czy jedne kategorie mają więcej ocen dobrych niż inne? Czyli czy po prostu książki z danej kategorii są lepiej oceniane? To bardziej precyzyjny obraz niż średnia ocena według kategorii - tutaj widać zróżnicowanie. Im szerszy słupek tym większy rozrzut. I na przykład taka motoryzacja jest w miarę zwarta. Jak bardzo? Ano:

books %>%
   filter(category == "motoryzacja", # jest w kategorii motoryzacja
   !is.na(score_mean)) %>% select(score_mean) %>% # i ma ocenę
   summary()
##    score_mean    
##  Min.   : 3.000  
##  1st Qu.: 6.700  
##  Median : 7.147  
##  Mean   : 7.129  
##  3rd Qu.: 7.756  
##  Max.   :10.000

Widać, że 1 i 3 kwartyl nie są tak bardzo od siebie oddalone. Czas na najciekawsze pytanie:

Jakie są najlepsze książki (według kategorii)?

Ano takie:

# górne 30% liczby ocen brane pod uwagę
books %>%
   filter(score_sum >= quantile(score_sum, 0.7, na.rm=TRUE)) %>%
   group_by(category) %>%
   mutate(cat_max_score = max(score_mean)) %>%
   ungroup() %>%
   filter(score_mean == cat_max_score) %>%
   select(category, title, author, score_mean) %>%
   mutate(score_mean = round(score_mean, 2)) %>%
   arrange(category)
KategoriaTytułAutorOcena
albumyWitold Pilecki. FotobiografiaMaciej Sadowski9.42
astronomia, astrofizykaNasz matematyczny Wszechświat. W poszukiwaniu prawdziwej natury rzeczywistościMax Tegmark8.56
bajkiBaśnie braci GrimmRuth Brocklehurst8.80
baśnie, legendy, podaniaBaśnie AndersenaHans Christian Andersen8.60
biografia/autobiografia/pamiętnikDziennik 1943-1948Sándor Márai9.36
biznes, finanseDzieła zebrane. T. 1Frédéric Bastiat9.29
czasopismaTeraz Rock. Kolekcja ‘po całości’, nr 8. Guns N’ RosesRedakcja magazynu Teraz Rock8.40
encyklopedie i słownikiMoja pierwsza encyklopedia zwierzątMarta Kotecka8.77
ezoteryka, senniki, horoskopyPrzywracanie zdrowiaDavid R. Hawkins9.40
fantastyka, fantasy, science fictionWojownicy. Cisza przed burząErin Hunter9.22
film/kino/telewizja33 x TrójkaWiesław Weiss8.43
filozofia i etykaBoża OpatrznośćCatalina Rivas9.44
flora i faunaPtaki. Przewodnik CollinsaLars Svensson9.32
historiaGetto Warszawskie. Przewodnik po nieistniejącym mieście.Barbara Engelking, Jacek Leociak9.30
historiaNarodziny cywilizacji Wysp BrytyjskichWojciech Lipoński9.30
historie biblijneBiblia8.73
historie biblijneBiblia to jest Pismo Święte Starego i Nowego Testamentu z Apokryfamiautor nieznany8.73
hobbyInwazja bazgrołów. Książka do kolorowaniaZifflin, Kerby Rosanes8.90
horrorThe Whisperer in Darkness: Collected Stories Volume IHoward Phillips Lovecraft8.45
informatyka i matematykaKod doskonały. Jak tworzyć oprogramowanie pozbawione błędówSteve McConnell9.06
inneCo chatka to zagadkaAndrzej Setman9.71
interaktywne, obrazkowe, edukacyjneMieszkamy w książce!Mo Willems9.21
językoznawstwo, nauka o literaturzeGwara warszawska dawniej i dziśBronisław Wieczorkiewicz8.67
klasykaherodot: dzieje9.17
komiksyŻycie i czasy Sknerusa McKwaczaDon Rosa9.24
kulinaria, przepisy kulinarneNajwyższa jakośćNA9.59
literatura dziecięcaWe mgleWalt Disney, Kiki Thorpe9.33
literatura faktuFotograf z AuschwitzAnna Dobrowolska9.03
literatura młodzieżowaElena. Tajemnica stadninyNele Neuhaus9.11
literatura obyczajowa i romansIliumJosephine Angelini9.06
literatura pięknaSiedem grzechów głuchychKaja Kowalewska9.60
literatura podróżniczaAmazonia - piekielne piękno. Kiedy przygoda zderza się z życiem9.25
literatura popularnonaukowaBiologiaNeil A. Campbell9.28
literatura współczesnaPlay listy, czyli nie wszystkie fobie są o miłościKaja Kowalewska9.28
militaria, wojskowośćPamiętnik (1941 -maj 1949)Zdzisław Broński8.96
motoryzacjaGawędy motocyklowepraca zbiorowa8.23
muzykaTysiąc i jedna operaPiotr Kamiński9.27
nauki przyrodnicze (fizyka, chemia, biologia, itd.)Feynmana wykłady z fizyki t. 1-3Richard Phillips Feynman8.94
nauki społeczne (psychologia, socjologia, itd.)Nowa PsychocybernetykaMaxwell Maltz9.33
opowiadania i powieściAmerican DaydreamJustyna Gaworska8.95
poezjanieskończoność M.YŚLIMagdalena Joanna Wojciechowska9.70
poradnikiŚwiatło jogiB. K. S. Iyengar9.15
poradniki dla rodzicówMama alergika gotuje tradycyjnieKatarzyna Jankowska8.25
pozostałeBiblia8.73
przygodowaDanzig Breslau DanzigAmos Oskar Ajchel9.20
publicystyka literacka i esejeListy z RzymuZbigniew Kadłubek9.36
religiaMądrość EwangeliiFrancesco Bersini9.60
rękodziełoCuda z modeliny. Techniki, materiały, pomysłySue Heaser8.24
rozrywkaNiesamowicie rozkoszne kotyStuart Macfarlane8.89
satyraJarek Patriota: Bóg, honor i włoszczyznaArtur Pruziński8.46
sportThe Book of BasketballBill Simmons9.50
sztukaHiroshige: Sto Słynnych Widoków EdoBichler Lorenz, Trede Melanie9.75
teatrPerformatyka: wstępRichard Schechner9.00
technikaTypografia książki. Podręcznik projektantaMichael Mitchell, Susan Wightman8.67
thriller/sensacja/kryminałPretty Lost DollsKer Dukey9.44
turystyka, mapy, atlasyPolska egzotyczna. Tom 2Grzegorz Rąkowski8.67
utwór dramatyczny (dramat, komedia, tragedia)Tragedie i kronikiWilliam Shakespeare9.47
wierszyki, piosenkiGupik ma szczęście!Tomek Nowaczyk8.94
zdrowie, medycynaZapalenie Tarczycy HashimotoIzabella Wentz MD, Marta Nowosadzka MD9.06

To jeszcze sprawdźmy jacy są

najlepsi autorzy (według kategorii)

# górne 30% liczby ocen brane pod uwagę
books %>%
   filter(score_sum >= quantile(score_sum, 0.7, na.rm=TRUE)) %>%
   group_by(category, author) %>%
   summarise(group_mean_score = mean(score_mean), n=n()) %>%
   ungroup() %>%
   group_by(category) %>%
   filter(group_mean_score == max(group_mean_score)) %>%
   ungroup() %>%
   select(category, author, mean_score=group_mean_score) %>%
   mutate(mean_score = round(mean_score, 2)) %>%
   arrange(category)
categoryauthormean_score
albumyMaciej Sadowski9.42
astronomia, astrofizykaMax Tegmark8.56
bajkiRuth Brocklehurst8.80
baśnie, legendy, podaniaMałgorzata Sobczak8.58
biografia/autobiografia/pamiętnikJan Rossman, Anna Zawadzka9.14
biznes, finanseBernard Fruga8.67
biznes, finanseOskar Jażdżyk8.67
czasopismaRedakcja pisma Trans/wizje8.07
encyklopedie i słownikiMarta Kotecka8.77
ezoteryka, senniki, horoskopyDavid R. Hawkins9.40
fantastyka, fantasy, science fictionS.L. Leśna9.12
film/kino/telewizjaWiesław Weiss8.43
filozofia i etykaCatalina Rivas9.44
flora i faunaLars Svensson9.32
historiaBarbara Engelking, Jacek Leociak9.30
historie biblijneautor nieznany8.73
hobbyZifflin, Kerby Rosanes8.90
horrorMichael Sims8.10
informatyka i matematykaSteve McConnell9.06
inneAndrzej Setman9.07
interaktywne, obrazkowe, edukacyjneMo Willems9.21
językoznawstwo, nauka o literaturzeBronisław Wieczorkiewicz8.67
klasykaJohn Milton8.71
komiksySergio Cariello, Doug Mauss9.00
komiksySteve Lieber, Matt Fraction i inni…9.00
kulinaria, przepisy kulinarneNA9.59
literatura dziecięcaTony Wolf, Jane Brierley i inni…9.28
literatura faktuAnna Dobrowolska9.03
literatura młodzieżowaNele Neuhaus8.93
literatura obyczajowa i romansJosephine Angelini9.06
literatura pięknaKaja Kowalewska9.60
literatura podróżniczaRafał Urbanelis9.00
literatura popularnonaukowaNeil A. Campbell9.28
literatura współczesnaKaja Kowalewska9.28
militaria, wojskowośćZdzisław Broński8.96
motoryzacjaWitold Rychter7.88
muzykaPiotr Kamiński9.27
nauki przyrodnicze (fizyka, chemia, biologia, itd.)Roger Penrose8.77
nauki społeczne (psychologia, socjologia, itd.)Maxwell Maltz9.33
opowiadania i powieściJustyna Gaworska8.95
poezjaMagdalena Joanna Wojciechowska9.70
poradnikiB. K. S. Iyengar9.15
poradniki dla rodzicówKatarzyna Jankowska8.25
pozostałeAgnieszka Kossowska8.65
przygodowaAmos Oskar Ajchel8.79
publicystyka literacka i esejeZbigniew Kadłubek9.36
religiaFrancesco Bersini9.60
rękodziełoSue Heaser8.24
rozrywkaStuart Macfarlane8.89
satyraArtur Pruziński8.46
sportBill Simmons9.50
sztukaBichler Lorenz, Trede Melanie9.75
teatrRichard Schechner9.00
technikaMichael Mitchell, Susan Wightman8.67
thriller/sensacja/kryminałKer Dukey9.44
turystyka, mapy, atlasyGrzegorz Rąkowski8.62
utwór dramatyczny (dramat, komedia, tragedia)Jarosław Borszewicz8.64
wierszyki, piosenkiTomek Nowaczyk8.94
zdrowie, medycynaIzabella Wentz MD, Marta Nowosadzka MD9.06

Nazwiska powinny się pokrywać z tabelą najlepszych książek. Chociaż nie musi oczywiście tak być. Przejdźmy do dziedziny czasu.

Książki według daty wydania

books %>%
   filter(date >= 1950, date <= 2017) %>%
   ggplot() +
   geom_histogram(aes(date), binwidth = 1, fill="lightgreen", color="black") +
   labs(x="Rok", y="Liczba książek") +
   scale_x_continuous(breaks = seq(1950, 2020, 5))

Serwis LubimyCzytać.pl istnieje od jakiegoś czasu i zapewne jest tak, że stara się mieć w bazie najnowsze książki (o nowościach dyskutuje się najchętniej) - stąd im bliżej “dzisiaj” tym więcej książek. Brakuje kompletu danych z lat 2015-2017, bo ich najzwyczajniej w świecie nie pobrałem (ileż można czekać…). Widać jednak wyraźną tendencję i sądzę, że w kolejnych latach słupki są po prostu wyższe (no, 2017 może być jeszcze niższy niż 2016 - w końcu rok jeszcze trwa).

Ocena w zależności od daty wydania

Czy data wydana książki ma wpływ na jej ocenę?

books %>%
   filter(date >= 1950, date <= 2017, !is.na(score_mean)) %>%
   filter(score_sum >= quantile(score_sum, 0.1)) %>%
   ggplot() +
   geom_jitter(aes(date, score_mean), color="lightgreen",
              height = 0, width = 0.25, alpha=0.2) +
   geom_smooth(aes(date, score_mean), se = FALSE, color="darkred", size=2) +
   labs(x="Rok", y="Średnia ocena") +
   scale_x_continuous(breaks = seq(1950, 2020, 10))

W zasadzie nie, chociaż dla najnowszych książek linia zawija się wyraźnie ku górze. Być może znaczenie ma liczba ocen?

Liczba ocen w zależności od daty wydania

books %>%
   filter(date >= 1950, date <= 2017, score_sum > 0) %>%
   filter(score_sum >= quantile(score_sum, 0.1)) %>%
   ggplot() +
   geom_jitter(aes(date, score_sum), color="lightgreen",
              height = 0, width = 0.25, alpha=0.2) +
   geom_smooth(aes(date, score_sum), se = FALSE, color="darkred", size=2) +
   scale_y_log10() +
   labs(x="Rok", y="Liczba ocen") +
   scale_x_continuous(breaks = seq(1950, 2020, 10))

Z linii trendu tego nie widać (ot, faluje sobie jakoś), ale kiedy popatrzymy na zagęszczenie punktów to wyraźnie dla nowszych książek jest więcej ocen. To może potwierdzać strategię serwisu (lub po prostu ludzką natruę) - chętniej dyskutujemy czy oceniamy nowości. A ci, którzy czytają dużo na pewno przeczytali klasykę, a teraz czytają na bieżąco to co ukazuje się na rynku. I na bieżąco oceniają nie pamiętając aby uzupełnić oceny książek, które dawno temu przeczytali (to mój problem na Filwebie - mimo pewnie już prawie dwóch tysięcy ocenionych filmów ciągle są takie, które widziałem dawno temu, a ich nie oceniłem). Oczywiście linia trendu spada po prawej stronie - brakuje nam danych to raz, a dwa - nie wszyscy przeczytali jeszcze te najnowsze książki. W końcu poziom czytelnictwa spada z roku na rok… A czy grube książki są lepsze?

Liczba stron a ocena

books %>%
   filter(!is.na(pages), !is.na(score_mean)) %>%
   filter(pages <= quantile(pages, 0.99), score_sum >= quantile(score_sum, 0.1)) %>%
   ggplot() +
   geom_point(aes(pages, score_mean), color="lightgreen", alpha=0.2) +
   geom_smooth(aes(pages, score_mean), se = FALSE, color="darkred", size=2) +
   labs(x="Liczba stron", y="Średnia ocena")

Liczba stron nie ma bardzo dużego znaczenia dla oceny książki, ale jakieś ma. Im grubsza książka tym wyższa ocena. Delikatnie, ale jednak. Troszeczkę. Nie bardzo. W sumie wokół średniej.

Liczba stron a liczba ocen

Czyli odpowiedź na pytanie czy wolimy czytać grube książki?

books %>%
   filter(!is.na(pages), score_sum > 0) %>%
   filter(pages <= quantile(pages, 0.99), score_sum >= quantile(score_sum, 0.1)) %>%
   ggplot() +
   geom_point(aes(pages, score_sum), color="lightgreen", alpha=0.2) +
   geom_smooth(aes(pages, score_sum), se = FALSE, color="darkred", size=2) +
   scale_y_log10() +
   labs(x="Liczba stron", y="Liczba ocen")

Dla liczby ocen znaczenie ma już liczba stron. Znowu trend tego nie pokazuje tak mocno jak gęstość punktów. Najwięcej ocen mają książki po 200-300 stron. Czyli te najpopularniejsze. Co ciekawe - kiedy narysujemy macierz ze współczynnikami korelacji to zależności pomiędzy rokiem (date), liczbą stron (pages), liczbą ocen (score_sum) i średnią oceną (score_mean) nie są zbyt mocne:

library(corrgram)
books %>%
   select(date, pages, score_mean, score_sum) %>%
   filter(date >= 1950, date <= 2017,
          score_sum >= mean(score_sum, na.rm = TRUE),
          pages <= quantile(pages, 0.99, na.rm = TRUE)) %>%
   corrgram(lower.panel = panel.shade, upper.panel = panel.cor)

Najsilniejsza zależność wiąże liczbę stron i średnią ocenę, co już widzieliśmy na wykresach z liniami trendu.

Najbardziej płodni autorzy

Czyich książek mamy najwięcej?

books %>%
   filter(!author %in% c("praca zbiorowa", "autor nieznany", "")) %>%
   select(author, title) %>%
   distinct() %>%
   count(author) %>%
   ungroup() %>%
   top_n(20, wt = n) %>%
   arrange(n) %>%
   mutate(author=factor(author, levels=unique(author))) %>%
   ggplot() +
   geom_bar(aes(author, n), stat="identity", color="black", fill="lightgreen") +
   geom_text(aes(author, n, label=n), hjust=1.2) +
   coord_flip() +
   theme(legend.position = "bottom") +
   labs(x="Autor", y="Liczba książek")

I tutaj niespodzianka. Walt Disney jako autor książek? Redakcja magazynu National Geographic naprowadza na trop (zerknięcie w kategorie też) - są to książeczki z komiksami dla dzieci, kolorowankami i innymi wydawnictwami tego typu. LubimyCzytać ma po prostu w bazie nie tylko książki (powieści, poezje i albumy) ale też czasopisma i inne periodyki. Druga sprawa: czy Verne napisał 174 książki? No raczej nie. Ale jego książki są:

  • wydawane przez różne wydawnictwa
  • wydawane w różnych językach
  • wydawane pod delikatnie różniącymi się tytułami (20000 mil - 8 sztuk, 20 000 mil - 7 sztuk, 20.000 mil - trzy sztuki, a to tylko przykład dla fragmentu jednego tytułu!)
  • wydawane w postaci całości lub podzielonej na tomy (Tom 1 albo część 1 albo cz.1 - super, co?)

Tutaj znowu kłania się porządek w danych i porządne słowniki. Czyli ta najbardziej upierdliwa rzecz w analityce, którą tutaj rozmyślnie odpuściłem. Ale to pokazuje też problem LubimyCzytać.pl (tylko czy oni potrzebują mieć to uporządkowane?).

W jakim języku są książki?

table(books$language) %>%
   as.data.frame() %>%
   mutate(p=100*Freq/sum(Freq)) %>%
   ggplot() +
   geom_bar(aes(Var1, p), stat="identity", fill="lightgreen", color="black") +
   geom_text(aes(Var1, p, label=paste(Freq, "egz.")), hjust=-0.1) +
   labs(x="Język", y="% zbioru") +
   scale_y_continuous(breaks = c(0,25,50,75,100), limits = c(0, 110)) +
   coord_flip()

Oczywiście w polskim serwisie jest najwięcej książek polskojęzycznych.

Powtarzające się tytuły

Czy są tytuły (całe, a nie fragmenty), które się powtarzają? Zobaczmy 20 najpopularniejszych:

books %>%
   count(title) %>%
   ungroup() %>%
   top_n(20) %>%
   arrange(desc(n))
titlen
Poezje178
Opowiadania129
Poezje wybrane113
Wiersze105
Wiersze wybrane83
Baśnie81
Wybór poezji71
Bajki66
Wspomnienia61
Pan Tadeusz56
Pamiętniki55
Mały Książę52
Przebudzenie52
Tajemniczy ogród51
Ania z Zielonego Wzgórza50
Dziedzictwo49
Listy49
Powrót49
Kopciuszek48
Pinokio46
W pustyni i w puszczy46

Odpowiedź brzmi: są. I są to mało zaskakujące tytuły. Zaskoczeniem może jedynie jest skala - Pan Tadeusz wydany w 56 wersjach, u-la-la! Pozostając przy tytułach zobaczmy czy są jakieś słowa, które w ramach danej kategorii są najbardziej popularne (w ramach tutułów)? To jest ciekawe! I jest duużo obrazków!

Najpopularniejsze słowa w tytułach - według kategorii

stop_words <- read_lines("../TwitterTrends_Raport/polish_stopwords.txt")

# rozbicie tytułów na poszczególne słowa, w ramach kategorii
words_by_cat <- books %>%
   # tytlko unikalna kombinacja tytuł-kategoria
   select(category, title) %>%
   distinct() %>%
   unnest_tokens(words, title, token="words") %>%
   # słowa dłuższe niż 2 znaki (eliminuje spójniki)
   filter(nchar(words) > 2) %>%
   count(category, words) %>%
   ungroup() %>%
   # wyrzucamy słowa nic nie znaczące, których jest bardzo dużo (głównie angielskie)
   filter(!words %in% c("the", "and", "tom", "vol", "volume", "part", "cz", "in", "for")) %>%
   # oraz polskie stop-words
   filter(!words %in% stop_words)

# dla każdej kategorii generujemy chmurkę max 50 słów
by(words_by_cat,
   words_by_cat$category,
   function(x) {
      wordcloud(x$words, x$n,
                max.words = 50,
                min.freq = median(x$n),
                scale = c(3.2, 0.5),
                colors = RColorBrewer::brewer.pal(9, "Greens")[4:9])
      text(0.05, 0.95, unique(x$category), col="darkred", cex=1.3,  adj=c(0,0))
      cat("\n")
   }
)

Zero zaskoczenia, całkowite zero.

Wszystkie kategorie

A jak wyglądają najpopularniejsze słowa, bez względu na kategorię? Wystarczy zagregować to co już mamy podzielone po kategoriach:

words_total <- words_by_cat %>%
   filter(n >= 3) %>%
   group_by(words) %>%
   summarise(n = sum(n)) %>%
   ungroup()

# chmurka słów - max 50 słów
wordcloud(words_total$words, words_total$n,
          scale = c(3.2, 0.5),
          max.words = 50,
          colors = RColorBrewer::brewer.pal(9, "Greens")[4:9])

Tutaj mam pewne wątpliwości - czy rzeczywiście historia to najbardziej popularne słowo w tytułach wśród 330 tysęcy książek? Według obliczeń występuje ono 4036 razy, a więc w 1.22% książek. Bardzo dużo, ja jestem szczerze zaskoczony. Ale może być tak, że w (pobranej) bazie serwisu jest jakaś nadreprezentacja danej kategorii. Być może serwis jest delikatnie ukierunkowany w stronę konkretnych odbiorców (piszemy trochę więcej o książkach historycznych, tak jak w jednej telewizji na abonament mówi się więcej o sukcesach rządu, a w takiej na reklamy - o jego wpadkach)? Tak czy inaczej - przydałaby się pełna, oczyszczona baza. Wówczas nasze analizy byłyby kompletne i nieco bardziej wiarygodne. Sprawdźmy więc czy jest nadreprezentacja którejś kategorii?

table(books$category) %>%
   prop.table() %>%
   as.data.frame() %>%
   mutate(Freq = 100 * Freq) %>%
   arrange(Freq) %>%
   mutate(Var1=factor(Var1, levels=Var1)) %>%
   ggplot() +
   geom_bar(aes(Var1, Freq), stat="identity", fill="lightgreen", color="black") +
   coord_flip() +
   labs(x="Kategoria", y="Udział procentowy w bazie")

No niestety jest… i to właśnie tej odpowiedzialnej za historię. Ale może tak właśnie wygląda rynek wydawniczy? W dalszych rozważaniach pominiemy tę kwestię, ale można pokusić się o znormalizowanie wartości zgodnie z powyższym wykresem - na przykład najprościej mnożąc liczbę słów przez liczbę, która określa jaką część stanowi kategoria (jeśli kategoria to 10% wszystkich książek - mnożymy prze 10, jeśli 5% - przez dwadzieścia. Krótko mówiąc: mnożymy przez 100/x). Co jeszcze można zrobić? Można przygotować chmurki najpopularniejszych bigramów (zbitek dwuwyrazowych) albo zrobić z bigramów graf, aby sprawdzić jakie słowa łączą się ze sobą, jak często i czy są kategorie gdzie dane połączenia są bardziej popularne. Wcześniej można oczyścić słowa z przypadków (sprowadzić je do mianowników) - pomocna może być hunspell_stem() z biblioteki hunspell (jest pakiet hunspell w CRAN). Można pokusić się o sprawdzenie czy popularność określonych słów w tytule zmienia się w zależności od daty wydania książki. To brzmi ciekawie, sprawdźmy więc!

words_by_year <- books %>%
   select(date, title) %>%
   # tylko przedział lat
   filter(date >= 1950, date <= 2017) %>%
   unnest_tokens(words, title, token="words") %>%
   count(date, words) %>%
   ungroup() %>%
   filter(nchar(words) > 2) %>%
   filter(!words %in% c("the", "and", "tom", "vol", "volume",
                        "part", "cz", "in", "for")) %>%
   filter(!words %in% stop_words)

Mamy przygotowane dane, zobaczmy liczbę książek ze słowem historia w tytule - jak zmieniała się w poszczególnych latach?

words_by_year %>%
   filter(words=="historia") %>%
   ggplot() +
   geom_bar(aes(date, n), stat="identity", fill="lightgreen", color="black") +
   labs(x="Rok", y="Liczba książek ze słowem \"historia\" w tytule") +
   scale_x_continuous(breaks = seq(1950, 2020, 5))

To są wartości bezwzględne co nie daje nam obrazu czy udział książek z historią w tytule rośnie czy nie. Wykes wygląda zresztą podobnie do tego z liczbą książek w poszczególnych latach. Zderzmy więc obie dane ze sobą i określmy procent książek z danym tytułem zamiast liczby bezwzględnej.

# liczba książek w roku
books_by_year <- books %>%
   count(date) %>%
   ungroup() %>%
   filter(date >= 1950, date <= 2017)

# łączymy liczbę słów w roku z liczbą książek w roku i liczymy procent
words_by_year_prop <- left_join(words_by_year, books_by_year, by="date") %>%
   mutate(prop = 100*n.x/n.y) %>%
   select(date, words, prop)

# wykres dla słowa "historia"
words_by_year_prop %>%
   filter(words=="historia") %>%
   ggplot() +
   geom_bar(aes(date, prop), stat="identity", fill="lightgreen", color="black") +
   labs(x="Rok", y="Liczba książek ze słowem \"historia\" w tytule") +
   scale_x_continuous(breaks = seq(1950, 2020, 5))

Jak widać proporcjonalnie książek ze słowem historia w tytule nie przybywa (i nie ubywa) jakoś bardzo, a różnice są na poziomie dziesiętnych części punktu procentowego. Tym bardziej jestem zaskoczony popularnością tego słowa (ale widząc nadreprezentację kategorii już mniej). Na koniec zobaczmy zatem sześć (akurat tyle, bo łatnie wygląda układ wykresów) najpopularniejszych słów w tytułach i ich zmianę w czasie:

# 6 najpopularniejszych słów
top_title_words <- words_total %>% top_n(6, wt=n) %>% .$words

words_by_year_prop %>%
   filter(words %in% top_title_words) %>%
   ggplot() +
   geom_bar(aes(date, prop, fill=words),
            stat="identity", color="black", show.legend = FALSE) +
   labs(x="Rok", y="Liczba książek z danym słowem w tytule") +
   scale_x_continuous(breaks = seq(1950, 2020, 10)) +
   facet_wrap(~words, ncol=2)

Najwyraźniej widać wzrost liczby przewodników. Dobierając odpowiednie słowa można znaleść też inne ciekawostki. Weźmy kilka słów: opowiadania, spider man (jako oddzielne słowa), prawo, ludzie, zarządzanie oraz star wars (też oddzielnie):

words_by_year_prop %>%
   filter(words %in% c("opowiadania", "spider", "man", "prawo",
                       "ludzie", "zarządzanie", "star", "wars")) %>%
   ggplot() +
   geom_bar(aes(date, prop, fill=words),
            stat="identity", color="black", show.legend = FALSE) +
   labs(x="Rok", y="Liczba książek z danym słowem w tytule") +
   scale_x_continuous(breaks = seq(1950, 2020, 10)) +
   facet_wrap(~words, ncol=2)

Tutaj widać wzrost od początku lat dwutysięcznych wydawnictw związanych z zarządzaniem, spada liczba książek ze zbiorem opowiadań (tak można wnioskować po wystąpieniach tego słowa w tytułach), widać wyraźną zbieżność słów spider i man (w latach 1960-1970 to pewnie komiksy, po roku 1990 to książeczki dla dzieci), podobnie dla Star Wars. Podobnie można prześledzić popularność poszczególnych autorów lub wydawnictw (ile tytułów zostało wydanych przez dane wydawnictwo w poszczególnych latach). Zestawiając dane o popularności wydawnictw z ich przychodami (o ile są dostępne na rynku, na przykład w raportach okresowych spółek) można próbować dobierać odpowiednie książki, które powinny być wydane aby zapewnić zysk. Oczywiście to bardzo uproszczone rozumowanie - w końcu nie oceniamy książek po okładce tytule. Może ktoś z Was ma pomysł? Podzielcie się w komentarzach!