Meistkommentierte Channels auf DERSTANDARD

Meistkommentierte Channels auf DERSTANDARD

Ich gestehe: Von Zeit zu Zeit bin ich, wenn auch nur passiv, einer dieser Kommentar-Junkies auf derstandard.at. Diese Neigung äußert sich vor allem in einem eigenartigen Leseverhalten. Über den ersten Absatz hinaus komme ich an manchen Tagen nur selten. Die Rekreationsfunktion nimmt ohnehin die Kommentarsektion weit mehr wahr, als es selbst polarisierende Gastkommentare vermögen (KrisenFrey sei als Beispiel angeführt). Dieser Lesertyp braucht im Grunde nur eine prägnante Überschrift (entsprechende Verfehlungen sind im Übrigen ein beliebtes Thema unter Postern) und ein stabiles Scrollrad der Maus (ich würde ja einen Link direkt nach der Überschrift nahelegen…). Außerdem muss sie/er wissen, wo gerade die Wogen hochgehen. Hier versuche ich das für den heutigen Tag nach Rubriken auszumachen:

import numpy as np
import pandas as pd
import re
import csv
import urllib2
from bs4 import BeautifulSoup

# links I want to scrape
link = [\
        "http://mobil.derstandard.at/Inland",\
        "http://mobil.derstandard.at/International",\
        "http://mobil.derstandard.at/Wirtschaft",\
        "http://mobil.derstandard.at/Web",\
        "http://mobil.derstandard.at/Sport",\
        "http://mobil.derstandard.at/Panorama",\
        "http://mobil.derstandard.at/Etat",\
        "http://mobil.derstandard.at/Kultur",\
        "http://mobil.derstandard.at/Wissenschaft",\
        "http://mobil.derstandard.at/Gesundheit",\
        "http://mobil.derstandard.at/Bildung",\
        "http://mobil.derstandard.at/Lifestyle",\
        "http://mobil.derstandard.at/Familie",\
        "http://mobil.derstandard.at/Meinung",\
]

# regexp pattern
r = re.compile("(^\\[\d)|\d.*Posting(s|)$")
vmatch = np.vectorize(lambda x:bool(r.match(x)))

x = []
commcount = pd.Series(x)
# extract posting counts and create a Series
for x in range(0, len(link)):
    y = urllib2.urlopen(link[x]).read()
    soup = BeautifulSoup(y)
    comm_text = soup.get_text(strip = True)
    df_comm = np.array([text for text in soup.stripped_strings])
    z = df_comm[vmatch(df_comm)]
    z = pd.Series(z)
    commcount[x] = z.str.replace(".Posting(s|)|^\\[|\\]$", "")

# create dataframe
df = pd.DataFrame()
for x in range(0, len(commcount)):
    df[x] = commcount[x]

# apply labels
df.columns = (["inland", "ausland", "wirtschaft", "web", "sport", \
               "panorama", "etat", "kultur", "wissenschaft", \
               "gesundheit", "bildung", "lifestyle", "familie", \
               "meinung"])

# write csv file
df.to_csv("comments_df.csv", sep=',', encoding='utf-8')
df <- read.table("comments_df.csv",
                sep              = ',',
                fileEncoding     = "utf-8",
                na.strings       = "",
                stringsAsFactors = F)

comm           <- rename(df, df[1, ])[-1, -1]
comm           <- sapply(comm, as.numeric)
(orig.labels   <- colnames(comm))
colnames(comm) <- substr(colnames(comm), 1, 3)
head(comm)
Tabelle 1 Teil der ausgelesenen Posting Counts
inl aus wir web spo pan eta kul wis ges bil lif fam mei
1 1 133 270 209 349 10 1 52 45 42 19 290 292
472 11 79 1 95 60 37 204 1 1 5 2 131 31
9 4 125 15 308 447 49 9 3 10 3 20 12 348
246 194 320 466 15 235 3 74 8 5 60 5 38 20
173 36 4 39 1 20 256 9 3 122 603 62 1 47
2 14 221 2 105 353 19 1 55 29 1 77 81 23
library(RColorBrewer)

comm        <- as.data.frame(comm)
fun         <- function(x) {median(x, na.rm = T)}
m           <- colwise(fun)(comm)
colnames(m) <- orig.labels
(m          <- m[order(m, decreasing = T)])
(df.median  <- as.data.frame(t(m)))

## capitalize labels
simpleCap <-
    function(x) {
        s <- strsplit(x, " ")[[1]]
        paste(toupper(substring(s, 1,1)), substring(s, 2),
              sep="", collapse=" ")
    }
(rownames(df.median) <-
    sapply(rownames(df.median), simpleCap))

pal2 <- brewer.pal(3, "Accent")

ggplot(df.median) + geom_bar(
    aes(factor(rownames(df.median), levels = rownames(df.median)),
        V1,
        fill = V1),
    stat = "identity") +
  labs(y = "Median der Postings pro Artikel",
       x = "Channel") +
  theme_classic() +
  theme(axis.text.x = element_text(size = 10, angle = 90)) +
  scale_fill_gradientn(colours = pal2) +
  guides(fill = F)

Etwas überrascht mich das Resultat dann doch. Dass beispielsweise Web so schlecht abschneidet, hingegen Panorama relativ gut, kommt unerwartet. Sport wird wohl wegen der Großereignisse ein bloß zwischenzeitliches Hoch erleben. Inland bewegt offenbar weit mehr als Ausland, die Nachrichtenwert-Theorie lässt grüßen.

medianpostings.png

Was die Aufmerksamkeit der Poster betrifft, so konzentriert sie sich auf wenige Artikel. Vieles geht sang- und klanglos unter. Welche Channels nun besonders davon betroffen sind, kann über Boxplots ausgewiesen werden. So zeigt sich, dass die Rubriken Meinung und Wirtschaft zwar ein konstant hohes Interesse wecken, die wirklich hohen Postingzahlen bleiben ihnen jedoch verwehrt. Diese finden wir vor allem in den Channels Inland, Sport und Familie.

library(reshape)

colnames(comm) <- sapply(orig.labels, simpleCap)
df.ordered     <- comm[rownames(df.median)]

meltData       <- melt(df.ordered)
## boxplot(data=meltData, value ~ variable)

ggplot(meltData, aes(factor(variable), value)) +
  geom_boxplot(aes(fill = variable)) +
  facet_wrap(~ variable, scale = "free") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.background  = element_blank(),
        axis.ticks       = element_blank(),
        axis.text.x      = element_blank(),
        strip.text.x     = element_text(size = 11)) +
  labs(y = "Postings pro Artikel",
       x = element_blank()) +
  scale_y_continuous() +
  scale_fill_hue(h.start = 100) +
  guides(fill = FALSE)
postings_wrap.png
R Python Parsing