Dieses Dokument beschreibt die Vorprozessierung und explorative Analyse des Datensatzes, der Grundlage des auf srf.ch veröffentlichten Artikel Diese Telekom-Anbieter sorgen für den meisten Unmut ist.
SRF Data legt Wert darauf, dass die Datenvorprozessierung und -Analyse nachvollzogen und überprüft werden kann. SRF Data glaubt an das Prinzip offener Daten, aber auch offener und nachvollziehbarer Methoden. Zum anderen soll es Dritten ermöglicht werden, auf dieser Vorarbeit aufzubauen und damit weitere Auswertungen oder Applikationen zu generieren.
Die Endprodukte des vorliegenden Scripts, neben der vorliegenden explorativen Analyse, sind (Datenbeschreibung siehe unten):
reasons_top_four_providers.csv
cases_per_type.csv
cases_top_4_with_exit.csv
Die Vorprozessierung und Analyse wurde im Statistikprogramm R vorgenommen. Das zugrunde liegende Script sowie die prozessierten Daten können unter diesem Link heruntergeladen werden. Durch Ausführen von main.Rmd
kann der hier beschriebene Prozess nachvollzogen und der für den Artikel verwendete Datensatz generiert werden. Dabei werden Daten aus dem Ordner input
eingelesen und Ergebnisse in den Ordner output
geschrieben.
SRF Data verwendet das rddj-template von Timo Grossenbacher als Grundlage für seine R-Scripts. Entstehen bei der Ausführung dieses Scripts Probleme, kann es helfen, die Anleitung von rddj-template zu studieren.
Debug-Informationen: This report was generated on 2019-11-19 14:12:02. R version: 3.5.3 on x86_64-pc-linux-gnu. For this report, CRAN packages as of 2019-03-01 were used.
Der Code für die vorliegende Datenprozessierung ist auf https://github.com/srfdata/2019-11-ombudscom zur freien Verwendung verfügbar.
2019-11-ombudscom von SRF Data ist lizenziert unter einer Creative Commons Namensnennung - Weitergabe unter gleichen Bedingungen 4.0 International Lizenz.
Code & Daten von SRF Data sind unter https://srfdata.github.io verfügbar.
Die veröffentlichten Informationen sind sorgfältig zusammengestellt, erheben aber keinen Anspruch auf Aktualität, Vollständigkeit oder Richtigkeit. Es wird keine Haftung übernommen für Schäden, die durch die Verwendung dieses Scripts oder der daraus gezogenen Informationen entstehen. Dies gilt ebenfalls für Inhalte Dritter, die über dieses Angebot zugänglich sind.
cases_per_type.csv
Attribut | Typ | Beschreibung |
---|---|---|
year | Numeric | Jahr der Beobachtung |
Fernmeldedienst | Numeric | Anzahl Fälle der Fernmeldedienstanbieter |
Mehrwertdienst | Numeric | Anzahl Fälle der Mehrwertdienstanbieter |
cases_top_4_with_exit.csv
Exportiert werden nur die drei aus unserer Sicht wichtigsten Ausgänge. Andere bezieht sich sowohl auf Fernmeldedienstanbieter wie auch auf Mehrwertdienstanbieter, auch hier sind die Jahre 2014-18 abgebildet.
Attribut | Typ | Beschreibung |
---|---|---|
category | String | Ausgang des Falls in Worten |
Salt | Numeric | Anzahl Fälle 2014-2018 mit diesem Ausgang bei Salt |
Sunrise | Numeric | Anzahl Fälle 2014-2018 mit diesem Ausgang bei Sunrise |
Swisscom | Numeric | Anzahl Fälle 2014-2018 mit diesem Ausgang bei Swisscom |
UPC | Numeric | Anzahl Fälle 2014-2018 mit diesem Ausgang bei UPC |
Andere | Numeric | Anzahl Fälle 2014-2018 mit diesem Ausgang bei allen anderen Providern |
reasons_top_four_providers.csv
Diese Zahlen beziehen sich nur auf die Fälle der 4 grössten Provider Salt, Sunrise, Swisscom und UPC, auch hier sind die Jahre 2014-18 abgebildet.
Attribut | Typ | Beschreibung |
---|---|---|
category | String | Beschwerdegrund |
value | Numeric | Anzahl Fälle 2014-2018 mit diesem Beschwerdegrund |
Originalquelle der Auswertungen sind Daten, die SRF im Rahmen des Öffentlichkeitsprinzips von der Ombudscom herausverlangt hat. Die betreffenden Excel-Dateien, die SRF zugeschickt worden waren, finden sich im Ordner input/data
.
Lesen Sie mehr über das Verfahren eines Ombudscom-Falls auf der betreffenden Website oder im letzten Bericht (2018). Wichtig ist uns die Unterscheidung zwischen einer Anfrage und einem Fall. Es wird wie folgt beschrieben: “Eine Anfrage wird statistisch erfasst, wenn sich eine Person schriftlich oder telefonisch an die Schlichtungsstelle wendet und die Voraussetzungen für eine Einleitung des Schlichtungsverfahrens gemäss Art. 8 Prozess- und Gebührenreglement noch nicht erfüllt sind.”
Das bedeutet, dass sich diese Analyse hauptsächlich auf die Fälle und nicht auf die Anfragen konzentriert. So wurden beispielsweise im Jahr 2018 die folgenden Untergruppen von Anfragen protokolliert:
Wie im Jahresbericht 2018 auf Seite 9 angegeben. Im Erklärungstext ist zu verstehen, dass die Anfragen allein vielleicht keine sehr zuverlässige Informationsquelle sind: “872 abgeschlossene Anfragen sind auf nicht eingereichte Dokumente zurückzuführen. Diese machten knapp 26% aller Anfragen aus. Gegenüber dem Vorjahr stieg dieser Wert leicht. Oft sind den Kundinnen und Kunden die Hürden zur Durchführung eines Schlichtungsverfahrens zu hoch. Bereits das Ausfüllen eines speziell für das Schlichtungsverfahren vorgesehenen Formulars bereitete einigen Personen Mühe. Oftmals gingen sie fälschlicherweise auch davon aus, dass der Ombudsmann ihre Interessen gegenüber den Anbietern vertritt oder die streitige Angelegenheit umgehend (z.B. mit einem Telefonat mit dem betroffenen Anbieter) lösen kann. Auch wurden sie von auf die Schlichtungsstelle verweisenden Stellen falsch über die Funktion und die Aufgaben der Schlichtungsstelle informiert. Die Mitarbeitenden der Schlichtungsstelle klärten die Kundinnen und Kunden über die Tätigkeit auf und informierten sie über die Eintretensvoraussetzungen: Bevor ein Schlichtungsverfahren eingeleitet werden kann, muss die begehrende Partei das Formular „Schlichtungsbegehren“ unter Angabe des Sachverhalts und Ziels ausfüllen sowie glaubhaft darlegen, dass sie sich innerhalb der letzten 12 Monate erfolglos um eine Lösung des Problems bemüht hatte. Ging aus der Anfrage nicht hervor, dass die Kundin oder der Kunde bereits eine Lösung mit dem Anbieter angestrebt hatte, empfahl die Schlichtungsstelle, sich schriftlich mit einer Beschwerde an den betroffenen Anbieter zu wenden. Dieser Aufwand war vielen Kundinnen und Kunden zu gross. Sie gingen – wie bereits erwähnt – davon aus, dass die Schlichtungsstelle ihre Interessen vertreten könne und sie in der Angelegenheit nichts weiter unternehmen müssen. Daher strebten sie kein Schlichtungsverfahren an und die Anfragen wurden infolge nicht eingereichter Dokumente abgeschlossen.”
## [1] "package package:rmarkdown detached"
## Loading required package: knitr
## Loading required package: rstudioapi
# from https://mran.revolutionanalytics.com/web/packages/checkpoint/vignettes/using-checkpoint-with-knitr.html
# if you don't need a package, remove it from here (commenting is probably not sufficient)
# tidyverse: see https://blog.rstudio.org/2016/09/15/tidyverse-1-0-0/
cat("
library(rstudioapi)
library(tidyverse) # ggplot2, dplyr, tidyr, readr, purrr, tibble
library(glue) # string literals
library(magrittr) # pipes
library(readxl) # excel
library(scales) # scales for ggplot2
library(jsonlite) # json
library(lintr) # code linting
library(ggrepel) # repelling geom_text
library(rmarkdown)",
file = "manifest.R")
# if checkpoint is not yet installed, install it (for people using this
# system for the first time)
if (!require(checkpoint)) {
if (!require(devtools)) {
install.packages("devtools", repos = "http://cran.us.r-project.org")
require(devtools)
}
devtools::install_github("RevolutionAnalytics/checkpoint",
ref = "v0.3.2", # could be adapted later,
# as of now (beginning of July 2017
# this is the current release on CRAN)
repos = "http://cran.us.r-project.org")
require(checkpoint)
}
# nolint start
if (!dir.exists("~/.checkpoint")) {
dir.create("~/.checkpoint")
}
# nolint end
# install packages for the specified CRAN snapshot date
checkpoint(snapshotDate = package_date,
project = path_to_wd,
verbose = T,
scanForPackages = F,
use.knitr = F,
R.version = R_version)
rm(package_date)
source("manifest.R")
unlink("manifest.R")
sessionInfo()
## R version 3.5.3 (2019-03-11)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.3 LTS
##
## Matrix products: default
## BLAS: /opt/R/R-3.5.3/lib/R/lib/libRblas.so
## LAPACK: /opt/R/R-3.5.3/lib/R/lib/libRlapack.so
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=de_CH.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=de_CH.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=de_CH.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=de_CH.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] rmarkdown_1.11 ggrepel_0.8.0 lintr_1.0.3 jsonlite_1.6
## [5] scales_1.0.0 readxl_1.3.0 magrittr_1.5 glue_1.3.0
## [9] forcats_0.4.0 stringr_1.4.0 dplyr_0.8.0.1 purrr_0.3.0
## [13] readr_1.3.1 tidyr_0.8.2 tibble_2.0.1 ggplot2_3.1.0
## [17] tidyverse_1.2.1 checkpoint_0.4.0 rstudioapi_0.9.0 knitr_1.21
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.0 cellranger_1.1.0 plyr_1.8.4 pillar_1.3.1
## [5] compiler_3.5.3 tools_3.5.3 digest_0.6.18 lubridate_1.7.4
## [9] evaluate_0.13 nlme_3.1-137 gtable_0.2.0 lattice_0.20-38
## [13] pkgconfig_2.0.2 rlang_0.3.1 rex_1.1.2 cli_1.0.1
## [17] yaml_2.2.0 haven_2.1.0 xfun_0.5 withr_2.1.2
## [21] xml2_1.2.0 httr_1.4.0 hms_0.4.2 generics_0.0.2
## [25] grid_3.5.3 tidyselect_0.2.5 R6_2.4.0 modelr_0.1.4
## [29] backports_1.1.3 htmltools_0.3.6 rvest_0.3.2 assertthat_0.2.0
## [33] colorspace_1.4-0 stringi_1.3.1 lazyeval_0.2.1 munsell_0.5.0
## [37] broom_0.5.1 crayon_1.3.4
rm(list = ls(all = TRUE))
# prepare multiple tibbles that will be filled with data
status <- tibble() # Statistik
reasons_cases_requests <- tibble() # Beschwerdegründe (Fälle und Anfragen)
reasons_cases <- tibble() # Beschwerdegründe (nur Fälle)
reasons_requests <- tibble() # Beschwerdegründe (nur Anfragen)
languages <- tibble() # Sprache Beschwerdeführer
appellant_types <- tibble() # Art Beschwerdeführer
avg_sums <- tibble() # Durchschnittliche Streitsummen
avg_durations <- tibble() # Durchschnittlichen Behandlungsdauer
# the files have a consistent structure
c("FDA", "MWDA") %>%
walk(function(current_type) {
list.files(
"input/data",
pattern = glue("^\\d{{4}}_{current_type}.xlsx$"),
full.names = TRUE
) %>%
walk(function(current_file) {
# create helper function that gathers providers
# renames first column to category and appends info about year/file
add_info_and_gather <- function(df) {
df %>%
rename(category = 1) %>%
mutate(
year = as.numeric(str_extract(current_file, "\\d{4}")),
type = str_replace_all(current_type, c(
"FDA" = "Fernmeldedienst",
"MWDA" = "Mehrwertdienst"
))
) %>%
gather(
key = "provider",
value = "value",
-one_of("category", "year", "type", "file")
) %>%
# convert to numeric, but first remove dots (thousands) and
# replace commas (decimal) with point
mutate(
value = str_replace_all(value, "\\.", ""),
value = str_replace_all(value, ",", "."),
value = as.numeric(value)
)
}
# read ranges and bind to prepared tibbles
suppressMessages({
status <<- status %>%
bind_rows(
read_excel(current_file, skip = 1, n_max = 37) %>%
add_info_and_gather()
)
reasons_cases_requests <<- reasons_cases_requests %>%
bind_rows(
read_excel(current_file, skip = 40, n_max = 22) %>%
add_info_and_gather()
)
reasons_cases <<- reasons_cases %>%
bind_rows(
read_excel(current_file, skip = 65, n_max = 22) %>%
add_info_and_gather()
)
reasons_requests <<- reasons_requests %>%
bind_rows(
read_excel(current_file, skip = 90, n_max = 22) %>%
add_info_and_gather()
)
languages <<- languages %>%
bind_rows(
read_excel(current_file, skip = 115, n_max = 4) %>%
add_info_and_gather()
)
appellant_types <<- appellant_types %>%
bind_rows(
read_excel(current_file, skip = 122, n_max = 3) %>%
add_info_and_gather()
)
avg_sums <<- avg_sums %>%
bind_rows(
read_excel(current_file, skip = 128, n_max = 2) %>%
add_info_and_gather()
)
avg_durations <<- avg_durations %>%
bind_rows(
read_excel(current_file, skip = 133, n_max = 8) %>%
add_info_and_gather()
)
})
})
})
# In our tables we still have some totals. Not only in the column category
# where it is the sum of all other categories, but also in the column provider
# we remove all these, we can sum stuff on our own perfectly well.
# Also convert category, type, provider to factor in all tibbles, don't be
# confused by the syntax with walk / assign, it's really just a fancy way
# to apply the same mutation to all variables named in the vector.
c(
"status",
"reasons_cases_requests",
"reasons_cases",
"reasons_requests",
"languages",
"appellant_types",
"avg_sums",
"avg_durations"
) %>%
walk(function(current_tibble) {
# create new variables with names …_totals
assign(
glue("{current_tibble}_totals"),
get(current_tibble) %>%
# now remove totals from original tables
filter(
str_detect(category, "^Total") |
str_detect(provider, "^Total")
),
envir = .GlobalEnv
)
# apply mutation to all variables
assign(
current_tibble,
get(current_tibble) %>%
# now remove totals from original tables
filter(
!str_detect(category, "^Total") &
!str_detect(provider, "^Total")
) %>%
mutate_at(
vars(category, type, provider),
factor
),
envir = .GlobalEnv
)
})
Die Tabelle status
enthält zwei Gruppen: Fälle
und Anfragen abgeschlossen
. In der Spalte category
sind auch die Unterkategorien aufgeführt, aber diese beiden sind geeignet, um sich die Summen pro Jahr anzusehen, z.B:
top_four <- c("Salt Mobile SA", "Swisscom (Schweiz) AG",
"Sunrise Communications AG", "UPC Schweiz GmbH")
status %>%
filter(category == "Fälle" | category == "Anfragen abgeschlossen") %>%
group_by(category, year) %>%
summarise(sum = sum(value)) %>%
spread(key = category, value = sum) %>%
mutate(Total = `Anfragen abgeschlossen` + `Fälle`) %>%
knitr::kable()
year | Anfragen abgeschlossen | Fälle | Total |
---|---|---|---|
2014 | 5036 | 1184 | 6220 |
2015 | 4849 | 1420 | 6269 |
2016 | 5115 | 1333 | 6448 |
2017 | 4183 | 1125 | 5308 |
2018 | 3330 | 1078 | 4408 |
status %>%
filter(category == "Fälle" | category == "Anfragen abgeschlossen") %>%
group_by(category, year, type) %>%
summarise(sum = sum(value)) %>%
ggplot(
aes(
x = year,
y = sum,
fill = type
)
) +
geom_bar(stat = "identity") +
scale_fill_brewer(palette = "Set1", guide = FALSE) +
facet_grid(category ~ type, scales = "fixed") +
theme_minimal() +
labs(
title = "Anzahl Fälle und Anfragen pro Jahr",
x = NULL,
y = NULL,
fill = NULL
)
# csv for graphic in article
write_csv(
status %>%
filter(category == "Fälle") %>%
select(-category) %>%
group_by(year, type) %>%
summarise(sum = sum(value)) %>%
spread(type, sum),
path = "output/cases_per_type.csv"
)
Die Anzahl der Anbieter / Provider scheint über Jahre hinweg einheitlich zu sein.
status %>%
distinct(type, provider, year) %>%
group_by(type, year) %>%
count() %>%
knitr::kable()
type | year | n |
---|---|---|
Fernmeldedienst | 2014 | 188 |
Fernmeldedienst | 2015 | 188 |
Fernmeldedienst | 2016 | 188 |
Fernmeldedienst | 2017 | 188 |
Fernmeldedienst | 2018 | 188 |
Mehrwertdienst | 2014 | 203 |
Mehrwertdienst | 2015 | 203 |
Mehrwertdienst | 2016 | 203 |
Mehrwertdienst | 2017 | 203 |
Mehrwertdienst | 2018 | 203 |
Nun identifizieren wir die “grossen Fische” über alle fünf Jahre hinweg, sortiert nach der Gesamtzahl der Fälle:
top_20 <- status %>%
filter(category == "Fälle") %>%
group_by(provider, type, category) %>%
summarise(sum = sum(value)) %>%
ungroup() %>%
spread(key = category, value = sum) %>%
arrange(desc(`Fälle`)) %>%
top_n(20)
top_20 %>%
knitr::kable()
provider | type | Fälle |
---|---|---|
Salt Mobile SA | Fernmeldedienst | 1354 |
Sunrise Communications AG | Fernmeldedienst | 734 |
primacall AG | Fernmeldedienst | 680 |
UPC Schweiz GmbH | Fernmeldedienst | 654 |
Suissephone Communications GmbH | Fernmeldedienst | 552 |
Swisscom (Schweiz) AG | Fernmeldedienst | 520 |
FREEFON AG | Fernmeldedienst | 222 |
Echovox SA | Mehrwertdienst | 180 |
Kira Consulting & Solutions AG | Mehrwertdienst | 156 |
NTH AG | Mehrwertdienst | 140 |
TalkEasy GmbH | Fernmeldedienst | 92 |
Richberg Media AG | Mehrwertdienst | 74 |
TalkTalk AG | Fernmeldedienst | 66 |
Dimoco Europe GmbH | Mehrwertdienst | 40 |
Buongiorno Schweiz AG | Mehrwertdienst | 39 |
OneCom GmbH | Fernmeldedienst | 39 |
Terrifix AG | Mehrwertdienst | 38 |
MOBIYO SAS | Mehrwertdienst | 29 |
MobileTrade AG | Mehrwertdienst | 26 |
TelCommunication Services AG | Fernmeldedienst | 23 |
top_20 %<>%
pull(provider)
# define a categorical color scale with looots of values
categorical <- c(
"#e31f2b", "#f7a600", "#a8b51c",
"#61b13e", "#1cb373", "#1cb0b5",
"#1e8ce3", "#a359c0", "#ca51af",
"#9f9c90" # grey
)
top_10 <- top_20[1:10]
status %>%
filter(
provider %in% top_10 &
category == "Fälle"
) %>%
ggplot(
aes(
x = year,
y = value,
group = provider,
color = provider
)
) +
geom_line() +
geom_text_repel(
data = status %>%
filter(
provider %in% top_10 &
year == max(year) &
category == "Fälle"
),
mapping = aes(
label = provider
),
segment.colour = "#DDDDDD",
direction = "y",
nudge_x = 0.5,
hjust = 0
) +
scale_color_manual(values = categorical) +
scale_x_continuous(
breaks = seq(min(status$year), max(status$year)),
limits = c(NA, max(avg_sums$year) + 3)
) +
theme_minimal() +
theme(legend.position = "none") +
labs(
title = "Anzahl Fälle der 10 Provider mit den meisten Fällen",
x = NULL,
y = NULL
)
Unter den Top-10-Anbietern mit den meisten Fällen analysieren wir auch die durchschnittliche Streitsumme pro Fall und Jahr:
avg_sums %>%
filter(
provider %in% top_10 &
category == "Streitsumme CHF"
) %>%
ggplot(
aes(
x = year,
y = value,
group = provider,
color = provider
)
) +
geom_line() +
geom_text_repel(
data = avg_sums %>%
filter(
provider %in% top_10 &
category == "Streitsumme CHF" &
year == max(year)
),
mapping = aes(
label = provider
),
segment.colour = "#DDDDDD",
direction = "y",
nudge_x = 0.5,
hjust = 0
) +
scale_y_log10(labels = dollar_format(prefix = "CHF")) +
scale_x_continuous(
breaks = seq(min(status$year), max(status$year)),
limits = c(NA, max(avg_sums$year) + 3)
) +
scale_color_manual(values = categorical) +
theme_minimal() +
theme(legend.position = "none") +
labs(
title =
"Durchschnittliche Streitsumme der 10 Provider mit den meisten Fällen",
subtitle = "Hinweis: Die y-Achse ist logarithmisch",
x = NULL,
y = NULL
)
Die Durchschnittssumme pro Fall der Top-10-Anbieter liegt in der Regel zwischen 100 und 500 Schweizer Franken, mit Ausnahme der UPC Schweiz GmbH im Jahr 2014, wo sie CHF 2’397 betrug.
Aufschlüsselung nach Rückzug, Schlichtung und Nicht-Schlichtung über alle Jahre und Top-10-Anbieter:
relevant_status <- c(
"Schlichtung zustande gekommen",
"Rückzug Kunde nach Einleitung",
"Schlichtung nicht zustande gekommen"
)
status %>%
filter(
category %in% relevant_status &
provider %in% top_10
) %>%
mutate(provider = factor(provider, levels = top_10)) %>%
ggplot(aes(
x = year,
y = value,
fill = category
)) +
geom_bar(stat = "identity") +
facet_wrap(~ provider) +
scale_fill_manual(values = c("#9d9d9d", "#e31f2b", "#61b13e")) +
theme_minimal() +
labs(
title = "Fälle und deren Ausgang nach Provider, Jahr und Kategorie",
subtitle = "Top 10 der Provider mit den meisten Fällen 2014-2018",
x = NULL,
y = NULL,
fill = NULL
)
# table for "top four"
status %>%
filter(
category %in% relevant_status &
provider %in% top_four
) %>%
group_by(provider, year) %>%
summarize(sum = sum(value)) %>%
knitr::kable()
provider | year | sum |
---|---|---|
Salt Mobile SA | 2014 | 239 |
Salt Mobile SA | 2015 | 347 |
Salt Mobile SA | 2016 | 320 |
Salt Mobile SA | 2017 | 210 |
Salt Mobile SA | 2018 | 238 |
Sunrise Communications AG | 2014 | 164 |
Sunrise Communications AG | 2015 | 151 |
Sunrise Communications AG | 2016 | 127 |
Sunrise Communications AG | 2017 | 147 |
Sunrise Communications AG | 2018 | 145 |
Swisscom (Schweiz) AG | 2014 | 53 |
Swisscom (Schweiz) AG | 2015 | 72 |
Swisscom (Schweiz) AG | 2016 | 158 |
Swisscom (Schweiz) AG | 2017 | 145 |
Swisscom (Schweiz) AG | 2018 | 92 |
UPC Schweiz GmbH | 2014 | 63 |
UPC Schweiz GmbH | 2015 | 107 |
UPC Schweiz GmbH | 2016 | 131 |
UPC Schweiz GmbH | 2017 | 191 |
UPC Schweiz GmbH | 2018 | 162 |
# csv for graphic in article
write_csv(
status %>%
filter(
category %in% relevant_status
) %>%
mutate(provider = if_else(
provider %in% top_four,
as.character(provider),
"Andere"
)) %>%
group_by(provider, category) %>%
summarise(value = sum(value)) %>%
spread(provider, value) %>%
select(
category,
`Salt` = `Salt Mobile SA`,
`Sunrise` = `Sunrise Communications AG`,
`Swisscom` = `Swisscom (Schweiz) AG`,
`UPC` = `UPC Schweiz GmbH`,
Andere
) %>%
mutate(category = factor(category, levels = c(
"Schlichtung nicht zustande gekommen",
"Schlichtung zustande gekommen",
"Rückzug Kunde nach Einleitung"
))) %>%
arrange(category),
path = "output/cases_top_4_with_exit.csv"
)
Nachfolgend werden die Daten aller Jahre zusammengefasst, die Rückzüge entfernt und die Einigungen / Ablehnungen genauer aufgeschlüsselt.
relevant_status <- c(
"Einigung zugunsten Kunde",
"Einigung zugunsten Provider",
"Einigung Kunde und Provider",
"Ablehnung Kunde",
"Ablehnung Provider",
"Ablehnung Kunde und Provider",
"Unzuständigkeit nach Einleitung",
"Rückzug Kunde nach Einleitung"
)
status_aggregated <- status %>%
filter(
category %in% relevant_status &
provider %in% top_10
) %>%
mutate(provider = factor(provider, levels = top_10)) %>%
mutate(category = factor(category, levels = relevant_status)) %>%
group_by(provider, category) %>%
summarize(total_category = sum(value)) %>%
ungroup()
status_aggregated %>%
ggplot(aes(
x = provider,
y = total_category,
fill = category
)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = c("#579d39", "#72bd51", "#b3df9f",
"#c91024", "#f1434a", "#ff9193", "#ffe6e6",
"#9d9d9d")) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1.2)) +
labs(
title = "Fälle und deren Ausgang nach Provider, 2014-2018",
subtitle = "Top 10 der Provider mit den meisten Fällen 2014-2018",
x = NULL,
y = NULL,
fill = NULL
)
# table for "top four"
status_aggregated %>%
filter(provider %in% top_four) %>%
knitr::kable()
provider | category | total_category |
---|---|---|
Salt Mobile SA | Einigung zugunsten Kunde | 118 |
Salt Mobile SA | Einigung zugunsten Provider | 10 |
Salt Mobile SA | Einigung Kunde und Provider | 355 |
Salt Mobile SA | Ablehnung Kunde | 81 |
Salt Mobile SA | Ablehnung Provider | 129 |
Salt Mobile SA | Ablehnung Kunde und Provider | 38 |
Salt Mobile SA | Unzuständigkeit nach Einleitung | 3 |
Salt Mobile SA | Rückzug Kunde nach Einleitung | 620 |
Sunrise Communications AG | Einigung zugunsten Kunde | 147 |
Sunrise Communications AG | Einigung zugunsten Provider | 9 |
Sunrise Communications AG | Einigung Kunde und Provider | 259 |
Sunrise Communications AG | Ablehnung Kunde | 56 |
Sunrise Communications AG | Ablehnung Provider | 30 |
Sunrise Communications AG | Ablehnung Kunde und Provider | 28 |
Sunrise Communications AG | Unzuständigkeit nach Einleitung | 1 |
Sunrise Communications AG | Rückzug Kunde nach Einleitung | 204 |
UPC Schweiz GmbH | Einigung zugunsten Kunde | 299 |
UPC Schweiz GmbH | Einigung zugunsten Provider | 12 |
UPC Schweiz GmbH | Einigung Kunde und Provider | 215 |
UPC Schweiz GmbH | Ablehnung Kunde | 45 |
UPC Schweiz GmbH | Ablehnung Provider | 14 |
UPC Schweiz GmbH | Ablehnung Kunde und Provider | 4 |
UPC Schweiz GmbH | Unzuständigkeit nach Einleitung | 2 |
UPC Schweiz GmbH | Rückzug Kunde nach Einleitung | 63 |
Swisscom (Schweiz) AG | Einigung zugunsten Kunde | 61 |
Swisscom (Schweiz) AG | Einigung zugunsten Provider | 8 |
Swisscom (Schweiz) AG | Einigung Kunde und Provider | 97 |
Swisscom (Schweiz) AG | Ablehnung Kunde | 56 |
Swisscom (Schweiz) AG | Ablehnung Provider | 29 |
Swisscom (Schweiz) AG | Ablehnung Kunde und Provider | 16 |
Swisscom (Schweiz) AG | Unzuständigkeit nach Einleitung | 1 |
Swisscom (Schweiz) AG | Rückzug Kunde nach Einleitung | 252 |
status_aggregated %>%
group_by(provider) %>%
mutate(share = round(total_category / sum(total_category), 2)) %>%
filter(str_detect(category, "Rückzug")) %>%
select(provider, share) %>%
arrange(desc(share)) %>%
knitr::kable()
provider | share |
---|---|
NTH AG | 0.69 |
FREEFON AG | 0.67 |
primacall AG | 0.66 |
Suissephone Communications GmbH | 0.64 |
Swisscom (Schweiz) AG | 0.48 |
Salt Mobile SA | 0.46 |
Echovox SA | 0.44 |
Sunrise Communications AG | 0.28 |
Kira Consulting & Solutions AG | 0.17 |
UPC Schweiz GmbH | 0.10 |
relevant_status <- c(
"Einigung zugunsten Kunde",
"Einigung zugunsten Provider",
"Einigung Kunde und Provider",
"Ablehnung Kunde",
"Ablehnung Provider",
"Ablehnung Kunde und Provider",
"Unzuständigkeit nach Einleitung"
)
status_aggregated <- status %>%
filter(
category %in% relevant_status &
provider %in% top_10
) %>%
mutate(provider = factor(provider, levels = top_10)) %>%
mutate(category = factor(category, levels = relevant_status)) %>%
group_by(provider, category) %>%
summarize(total_category = sum(value)) %>%
ungroup()
status_aggregated %>%
ggplot(aes(
x = provider,
y = total_category,
fill = category
)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = c("#579d39", "#72bd51", "#b3df9f",
"#c91024", "#f1434a", "#ff9193", "#ffe6e6",
"#9d9d9d")) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1.2)) +
labs(
title = "Fälle und deren Ausgang nach Provider, 2014-2018",
subtitle = "Top 10 der Provider mit den meisten Fällen 2014-2018",
x = NULL,
y = NULL,
fill = NULL
)
status_aggregated %>%
filter(!str_detect(category, "Rückzug")) %>%
mutate(agg = word(category, 1)) %>%
group_by(provider, agg) %>%
summarize(total_category = sum(total_category)) %>%
mutate(share = round(total_category / sum(total_category), 2)) %>%
filter(str_detect(agg, "Einigung")) %>%
select(provider, share) %>%
arrange(desc(share)) %>%
knitr::kable()
provider | share |
---|---|
NTH AG | 0.93 |
Echovox SA | 0.90 |
UPC Schweiz GmbH | 0.89 |
FREEFON AG | 0.88 |
primacall AG | 0.82 |
Sunrise Communications AG | 0.78 |
Salt Mobile SA | 0.66 |
Swisscom (Schweiz) AG | 0.62 |
Suissephone Communications GmbH | 0.48 |
Kira Consulting & Solutions AG | 0.42 |
# get top n reasons
top_n_reasons <- reasons_cases %>%
group_by(category) %>%
summarize(total_category = sum(value)) %>%
arrange(desc(total_category)) %>%
top_n(9) %>%
pull(category)
reasons_cases %>%
filter(
provider %in% top_10
) %>%
# keep top 10 categories and summarize rest
mutate(category = case_when(
category %in% top_n_reasons ~ as.character(category),
TRUE ~ "Sonstige"
)) %>%
mutate(provider = factor(provider, levels = top_10)) %>%
mutate(category = factor(category, levels =
c(as.character(top_n_reasons), "Sonstige"))) %>%
group_by(provider, category) %>%
summarize(total_category = sum(value)) %>%
ungroup() %>%
ggplot(aes(
x = provider,
y = total_category,
fill = category
)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = categorical) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1.2)) +
labs(
title = "Beschwerdegründe (Fälle) nach Provider, 2014-2018",
subtitle = "Top 10 der Provider mit den meisten Fällen 2014-2018",
x = NULL,
y = NULL,
fill = NULL
)
# table for "top four"
reasons_cases %>%
filter(provider %in% top_four) %>% # keep top 10 categories and summarize rest
mutate(category = case_when(
category %in% top_n_reasons ~ as.character(category),
TRUE ~ "Sonstige"
)) %>%
group_by(provider, category) %>%
summarize(sum = sum(value)) %>%
ungroup() %>%
group_by(provider) %>%
arrange(provider, desc(sum)) %>%
knitr::kable()
provider | category | sum |
---|---|---|
Salt Mobile SA | Rechnungsstellung allg. | 564 |
Salt Mobile SA | Sperrung/Annulation Dienstleistung, Vertragskündigung | 375 |
Salt Mobile SA | Roaming | 177 |
Salt Mobile SA | Sonstige | 123 |
Salt Mobile SA | Kundendienst | 54 |
Salt Mobile SA | Unverlangte Dienstleistung | 25 |
Salt Mobile SA | MWD allg. | 21 |
Salt Mobile SA | Versorgungsqualität Festnetz | 11 |
Salt Mobile SA | MWD Erwachsenenunterhaltung | 2 |
Salt Mobile SA | Preselection | 2 |
Sunrise Communications AG | Rechnungsstellung allg. | 278 |
Sunrise Communications AG | Sperrung/Annulation Dienstleistung, Vertragskündigung | 193 |
Sunrise Communications AG | Roaming | 95 |
Sunrise Communications AG | Sonstige | 75 |
Sunrise Communications AG | Versorgungsqualität Festnetz | 31 |
Sunrise Communications AG | Kundendienst | 24 |
Sunrise Communications AG | Unverlangte Dienstleistung | 18 |
Sunrise Communications AG | MWD allg. | 12 |
Sunrise Communications AG | Preselection | 4 |
Sunrise Communications AG | MWD Erwachsenenunterhaltung | 1 |
Swisscom (Schweiz) AG | Rechnungsstellung allg. | 165 |
Swisscom (Schweiz) AG | Sperrung/Annulation Dienstleistung, Vertragskündigung | 98 |
Swisscom (Schweiz) AG | Sonstige | 92 |
Swisscom (Schweiz) AG | Versorgungsqualität Festnetz | 54 |
Swisscom (Schweiz) AG | MWD allg. | 40 |
Swisscom (Schweiz) AG | Kundendienst | 24 |
Swisscom (Schweiz) AG | Roaming | 24 |
Swisscom (Schweiz) AG | Unverlangte Dienstleistung | 14 |
Swisscom (Schweiz) AG | MWD Erwachsenenunterhaltung | 3 |
Swisscom (Schweiz) AG | Preselection | 0 |
UPC Schweiz GmbH | Rechnungsstellung allg. | 305 |
UPC Schweiz GmbH | Sperrung/Annulation Dienstleistung, Vertragskündigung | 204 |
UPC Schweiz GmbH | Unverlangte Dienstleistung | 43 |
UPC Schweiz GmbH | Sonstige | 34 |
UPC Schweiz GmbH | Versorgungsqualität Festnetz | 32 |
UPC Schweiz GmbH | Kundendienst | 21 |
UPC Schweiz GmbH | Roaming | 8 |
UPC Schweiz GmbH | MWD allg. | 1 |
UPC Schweiz GmbH | MWD Erwachsenenunterhaltung | 0 |
UPC Schweiz GmbH | Preselection | 0 |
# csv for graphic in article
write_csv(
reasons_cases %>%
filter(provider %in% top_four) %>%
group_by(category) %>%
summarise(value = sum(value)) %>%
arrange(desc(value)),
path = "output/reasons_top_four_providers.csv"
)
reasons_cases %>%
# keep top 10 categories and summarize rest
mutate(category = case_when(
category %in% top_n_reasons ~ as.character(category),
TRUE ~ "Sonstige"
)) %>%
mutate(category = factor(category, levels =
c(as.character(top_n_reasons), "Sonstige"))) %>%
group_by(category) %>%
summarize(total = sum(value)) %>%
knitr::kable()
category | total |
---|---|
Rechnungsstellung allg. | 1431 |
Preselection | 1227 |
Sperrung/Annulation Dienstleistung, Vertragskündigung | 1131 |
MWD allg. | 788 |
Roaming | 311 |
Unverlangte Dienstleistung | 269 |
MWD Erwachsenenunterhaltung | 197 |
Versorgungsqualität Festnetz | 182 |
Kundendienst | 133 |
Sonstige | 428 |
Der Code in diesem RMarkdown wird mit lintr automatisch auf den Wickham’schen tidyverse style guide überprüft.
lintr::lint("main.Rmd", linters =
lintr::with_defaults(
object_length_linter = object_length_linter(45)
)
)
## main.Rmd:667:15: style: Variable and function names should be all lowercase.
## `UPC` = `UPC Schweiz GmbH`,
## ^~~~~~~~~~~~~~~~~~