Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7166d1578 | ||
|
|
896ba1b3b0 | ||
|
|
ecb5677703 | ||
|
|
9d456bfa60 | ||
|
|
62fe9d497d | ||
|
|
29a7974941 | ||
|
|
e31ccabf18 | ||
|
|
622fd4db07 | ||
|
|
6aa80534f8 | ||
|
|
605e5e976a | ||
|
|
8e691e5d11 | ||
|
|
6b1f8a64b2 | ||
|
|
7e304d12bb | ||
|
|
864c0016cc | ||
|
|
489254dadf | ||
|
|
b09742815a | ||
|
|
7daf9e553c | ||
|
|
d657ca3fbe | ||
|
|
c53d842a1e | ||
|
|
f753920d34 |
+15
-7
@@ -1,13 +1,21 @@
|
|||||||
Package: hateimparlament
|
Package: hateimparlament
|
||||||
Title: Protocolanalysis of German Bundestag
|
Title: Recordanalysis Of Bundestag
|
||||||
Version: 0.0.0.9000
|
Version: 0.0.0.9000
|
||||||
Authors@R:
|
Authors@R: c(
|
||||||
person(given = "First",
|
person(given = "Leon",
|
||||||
family = "Last",
|
family = "Burgard",
|
||||||
|
role = c("aut")),
|
||||||
|
person(given = "Josua",
|
||||||
|
family = "Kugler",
|
||||||
|
role = c("aut")),
|
||||||
|
person(given = "Christian",
|
||||||
|
family = "Merten",
|
||||||
role = c("aut", "cre"),
|
role = c("aut", "cre"),
|
||||||
email = "first.last@example.com",
|
email = "christian@merten.dev"))
|
||||||
comment = c(ORCID = "YOUR-ORCID-ID"))
|
Description: Downloads, parses and analyses parliamentary records of the 19th legislative
|
||||||
Description: Downloads, parses and analyses protocols of the current German parliament (Bundestag).
|
period of the German parliament (Bundestag).
|
||||||
|
URL: https://git.flavigny.de/christian/hateimparlament
|
||||||
|
BugReports: https://git.flavigny.de/christian/hateimparlament/issues
|
||||||
License: GPL (>= 3)
|
License: GPL (>= 3)
|
||||||
Encoding: UTF-8
|
Encoding: UTF-8
|
||||||
LazyData: true
|
LazyData: true
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export(join_speaker)
|
|||||||
export(party_colors)
|
export(party_colors)
|
||||||
export(read_all)
|
export(read_all)
|
||||||
export(read_from_csv)
|
export(read_from_csv)
|
||||||
|
export(read_from_csv_or_fetch)
|
||||||
export(repair)
|
export(repair)
|
||||||
export(word_usage_by_date)
|
export(word_usage_by_date)
|
||||||
export(write_to_csv)
|
export(write_to_csv)
|
||||||
|
|||||||
@@ -61,10 +61,3 @@ fetch_all <- function(download_dir="inst/records/", create=FALSE) {
|
|||||||
# if successful, set progressbar to 100%
|
# if successful, set progressbar to 100%
|
||||||
setTimerProgressBar(pb, 250)
|
setTimerProgressBar(pb, 250)
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_dir_not_creatable <- function(cond) {
|
|
||||||
# currently this has call: dir.create(download_dir)
|
|
||||||
# do we want to change this to fetch_all(...) ?
|
|
||||||
cond$message <- "Directory does not exist and can't be created. Probably because the path is not writeable."
|
|
||||||
stop(cond)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ check_directory <- function(path, create=F) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop_dir_not_creatable <- function(cond) {
|
||||||
|
# currently this has call: dir.create(download_dir)
|
||||||
|
# do we want to change this to fetch_all(...) ?
|
||||||
|
cond$message <- "Directory does not exist and can't be created. Probably because the path is not writeable."
|
||||||
|
stop(cond)
|
||||||
|
}
|
||||||
|
|
||||||
# appends a file seperator at end of path if needed
|
# appends a file seperator at end of path if needed
|
||||||
make_directory_path <- function(path) {
|
make_directory_path <- function(path) {
|
||||||
if (!str_ends(path, .Platform$file.sep)) str_c(path, .Platform$file.sep)
|
if (!str_ends(path, .Platform$file.sep)) str_c(path, .Platform$file.sep)
|
||||||
|
|||||||
@@ -233,6 +233,11 @@ parse_speakerlist <- function(speakerliste_xml) {
|
|||||||
#'
|
#'
|
||||||
#' @export
|
#' @export
|
||||||
write_to_csv <- function(tables, path="inst/csv/", create=F) {
|
write_to_csv <- function(tables, path="inst/csv/", create=F) {
|
||||||
|
is_valid_res(tables)
|
||||||
|
stopifnot("path must be of type character" = is.character(path))
|
||||||
|
stopifnot("create must be of type logical" = is.logical(create))
|
||||||
|
|
||||||
|
path <- make_directory_path(path)
|
||||||
check_directory(path, create)
|
check_directory(path, create)
|
||||||
write.table(tables$speaker, str_c(path, "speaker.csv"))
|
write.table(tables$speaker, str_c(path, "speaker.csv"))
|
||||||
write.table(tables$speeches, str_c(path, "speeches.csv"))
|
write.table(tables$speeches, str_c(path, "speeches.csv"))
|
||||||
@@ -250,6 +255,9 @@ write_to_csv <- function(tables, path="inst/csv/", create=F) {
|
|||||||
#'
|
#'
|
||||||
#' @export
|
#' @export
|
||||||
read_from_csv <- function(path="inst/csv/") {
|
read_from_csv <- function(path="inst/csv/") {
|
||||||
|
stopifnot("path must be of type character" = is.character(path))
|
||||||
|
|
||||||
|
path <- make_directory_path(path)
|
||||||
list(speaker = read.table(str_c(path, "speaker.csv")) %>%
|
list(speaker = read.table(str_c(path, "speaker.csv")) %>%
|
||||||
tibble() %>%
|
tibble() %>%
|
||||||
mutate(id = as.character(id)),
|
mutate(id = as.character(id)),
|
||||||
@@ -259,5 +267,26 @@ read_from_csv <- function(path="inst/csv/") {
|
|||||||
date = as.Date(date)),
|
date = as.Date(date)),
|
||||||
talks = tibble %$% read.table(str_c(path, "talks.csv")),
|
talks = tibble %$% read.table(str_c(path, "talks.csv")),
|
||||||
comments = tibble %$% read.table(str_c(path, "comments.csv")),
|
comments = tibble %$% read.table(str_c(path, "comments.csv")),
|
||||||
applause = tibble %$% read.table(str_c(path, "applause.csv")))
|
applause = tibble %$% read.table(str_c(path, "applause.csv"))) -> res
|
||||||
|
is_valid_res(res)
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#' @param path directory of csv files to read
|
||||||
|
#' read data from csv files if they exist already
|
||||||
|
#' otherwise fetch protocols and then write the data into csv files
|
||||||
|
#'
|
||||||
|
#' @export
|
||||||
|
read_from_csv_or_fetch <- function(path="inst/") {
|
||||||
|
path <- make_directory_path(path)
|
||||||
|
res <- tryCatch(read_from_csv(str_c(path, "csv/")),
|
||||||
|
error = function(c) NULL)
|
||||||
|
if (!is.null(res)) return(res)
|
||||||
|
|
||||||
|
fetch_all(str_c(path, "records/"), create=T)
|
||||||
|
read_all(str_c(path, "records/")) %>%
|
||||||
|
repair() ->
|
||||||
|
res
|
||||||
|
write_to_csv(res, str_c(path, "csv/"), create=T)
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,147 @@
|
|||||||
# How to develop
|
# Description
|
||||||
|
|
||||||
|
R package to analyze parliamentary records of the 19th legislative period of the Bundestag,
|
||||||
|
the German parliament.
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
Using the `remotes` package, this is easily installed via:
|
||||||
|
```r
|
||||||
|
remotes::install_url("https://git.flavigny.de/christian/hateimparlament/archive/master.zip")
|
||||||
|
```
|
||||||
|
If you want to build the vignettes, pass `build_vignettes = TRUE`.
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
The package mainly supplies 4 functionalities:
|
||||||
|
|
||||||
|
## Download records
|
||||||
|
|
||||||
|
To analyze records, they need to be downloaded. This is done with `fetch_all`:
|
||||||
|
```r
|
||||||
|
fetch_all("records/", create = TRUE) # path to directory where records should be stored
|
||||||
|
```
|
||||||
|
This downloads all parliamentary records and stores them as `.xml` files in the given directory.
|
||||||
|
|
||||||
|
## Parse records
|
||||||
|
|
||||||
|
To use the records in R, they are converted to `tibble`s with
|
||||||
|
```r
|
||||||
|
res_raw <- read_all("records/") # path to directory where records are stored
|
||||||
|
```
|
||||||
|
|
||||||
|
`res_raw` is a named list with 5 `tibble`s:
|
||||||
|
|
||||||
|
### Speaker
|
||||||
|
|
||||||
|
Table of all speakers of this legislative period.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- `id`: Unique speaker id
|
||||||
|
- `prename`: Prename
|
||||||
|
- `lastname`: Surname
|
||||||
|
- `fraction`: Name of fraction if the speaker is member of parliament.
|
||||||
|
- `title`: Title, e.g. ,,Prof''
|
||||||
|
- `role_short`: Short name of role, e.g. ,,Bundeskanzlerin''
|
||||||
|
- `role_long`: Long name of role
|
||||||
|
|
||||||
|
### Speeches
|
||||||
|
|
||||||
|
Table of all speeches given during this legislative period.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- `id`: Unique speech id
|
||||||
|
- `speaker`: Principal speaker (the person standing behind the lectern during the speech).
|
||||||
|
- `date`: Date of session
|
||||||
|
|
||||||
|
### Talks
|
||||||
|
|
||||||
|
Within a speech, there can be multiple talks by different people. Mostly this is the main speech
|
||||||
|
by the principal speaker, but usually there are questions by other members of parliament or
|
||||||
|
order calls by the president of the Bundestag.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- `speech_id`: Speech in which this talk has been given
|
||||||
|
- `speaker`: Person that actually talks
|
||||||
|
- `content`: Spoken content
|
||||||
|
|
||||||
|
### Comments
|
||||||
|
|
||||||
|
These are the interjections that appear during the speeches.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- `speech_id`: The speech that was interrupted
|
||||||
|
- `on_speaker`: The speaker who was interrupted
|
||||||
|
- `fraction`: The fraction of the commenter
|
||||||
|
- `commenter`: The person who interrupted the speech
|
||||||
|
- `comment`: The content of the comment
|
||||||
|
|
||||||
|
### Applause
|
||||||
|
|
||||||
|
Table containing all the rounds of applause that happened during this legislative period.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- `speech_id`: Speech during which was applauded
|
||||||
|
- `on_speaker`: Speaker who was applauded
|
||||||
|
|
||||||
|
And then logical fields `CDU_CSU`, `SPD`, `FDP`, `DIE_LINKE`, `BUENDNIS_90_DIE_GRUENEN`, `AfD`
|
||||||
|
for every fraction in the Bundestag, signifying whether this fraction applauded.
|
||||||
|
|
||||||
|
## Repair records
|
||||||
|
|
||||||
|
The parliamentary records usually contain some major and minor formatting issues. These are
|
||||||
|
mostly resolved by using
|
||||||
|
```
|
||||||
|
res <- repair(res_raw)
|
||||||
|
```
|
||||||
|
By passing `lookup_speaker = TRUE`, even commenters in
|
||||||
|
`res_raw$comments` are matched with their respective speaker id.
|
||||||
|
|
||||||
|
## Analysis
|
||||||
|
|
||||||
|
Also some functions are provided to analyze the parliamentary records and draw some plots:
|
||||||
|
|
||||||
|
- `bar_plot_fractions`
|
||||||
|
- `find_word`
|
||||||
|
- `join_speaker`
|
||||||
|
- `word_usage_by_date`
|
||||||
|
|
||||||
|
See their usage with the `?` operator.
|
||||||
|
|
||||||
|
In the vignettes you can find different analyses of the protocols, for example:
|
||||||
|
|
||||||
|
- "Who talks the most?"
|
||||||
|
- "Which party gives the most speeches?"
|
||||||
|
- "Which party comments the most on which parties?"
|
||||||
|
- "When are which topics discussed the most?"
|
||||||
|
- ...
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Developing works the easiest with `devtools`:
|
||||||
```r
|
```r
|
||||||
# everything works with devtools (loads some other packages too)
|
|
||||||
library(devtools)
|
library(devtools)
|
||||||
|
```
|
||||||
# reload all package functions
|
When you changed something or added some functionality, you can reload all package functions with
|
||||||
|
```r
|
||||||
load_all()
|
load_all()
|
||||||
|
```
|
||||||
|
If you want to avoid reading all records every time you start a new R session, you can
|
||||||
|
write your parsed tibbles to CSV files:
|
||||||
|
|
||||||
#write to CSV files to speed up loading
|
```
|
||||||
tables <- read_all()
|
tables <- read_all()
|
||||||
tables <- repair(tables)
|
tables <- repair(tables)
|
||||||
write_to_csv(tables)
|
write_to_csv(tables, "path/to/csv/")
|
||||||
```
|
```
|
||||||
We NEVER use source(...), etc.! Also NEVER use library(...).
|
Then later you can use
|
||||||
But to add new packages (as dependency), use:
|
```r
|
||||||
|
res <- read_from_csv("path/to/csv/")
|
||||||
|
```
|
||||||
|
to load your stored tibbles very fast.
|
||||||
|
|
||||||
|
NEVER use source(...), etc.! Also NEVER use library(...).
|
||||||
|
To add new packages (as dependency), use:
|
||||||
```r
|
```r
|
||||||
use_package("my-good-old-package")
|
use_package("my-good-old-package")
|
||||||
```
|
```
|
||||||
@@ -27,87 +155,5 @@ document()
|
|||||||
|
|
||||||
Build vignettes
|
Build vignettes
|
||||||
```r
|
```r
|
||||||
rmarkdown::render("vignettes/bla.Rmd")
|
rmarkdown::render("vignettes/test.Rmd")
|
||||||
```
|
```
|
||||||
|
|
||||||
# Download
|
|
||||||
|
|
||||||
Before parsing, fetch.R must be run to download all protocols.
|
|
||||||
```r
|
|
||||||
fetch_all("../inst/records/") # path to directory where records should be stored
|
|
||||||
```
|
|
||||||
|
|
||||||
# Parsing
|
|
||||||
|
|
||||||
## tables
|
|
||||||
|
|
||||||
parse.R parses all downloaded logs and creates 5 tibbles.
|
|
||||||
repair.R then cleans up the errors in these tibbles.
|
|
||||||
```r
|
|
||||||
read_all("../inst/records/") %>% repair()
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Speaker
|
|
||||||
|
|
||||||
structure: `id` , `first_name` , `last_name` , `fraction` , `title` , `role_short`, `role_long`.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Obtained from the `<speaker list>` entry at the end of the transcripts.
|
|
||||||
|
|
||||||
### Speeches
|
|
||||||
|
|
||||||
Structure: `id` , `speaker`
|
|
||||||
|
|
||||||
The speeches `id` is specified in the protocol and is unique.A speech is a `<speech>` entry in the session history. A speech always has a main speaker (the one standing at the front of the lectern).
|
|
||||||
|
|
||||||
Within a speech, there can be different speech entries:
|
|
||||||
|
|
||||||
- Comments: Applause, interjections, etc.
|
|
||||||
- Speeches: Typically mainly the main speaker, but also interjections.
|
|
||||||
These are stored in the talks, comments and applause tables when parsing.
|
|
||||||
|
|
||||||
|
|
||||||
### Talks
|
|
||||||
|
|
||||||
Structure: `speech_id` , `speaker` , `content`.
|
|
||||||
|
|
||||||
These are the actual talk entries that appear within _speeches_.
|
|
||||||
|
|
||||||
- `speech_id`: the speech in which the contribution appears.
|
|
||||||
- `speaker`: The speaker of the speech entry.
|
|
||||||
- `content`: The content of the speech.
|
|
||||||
|
|
||||||
###comments
|
|
||||||
|
|
||||||
These are the interjections that appear during the speeches.
|
|
||||||
|
|
||||||
They have the following structure:
|
|
||||||
- `speech_id`: The speech that was interrupted.
|
|
||||||
- `on_speaker`: The speaker who was interrupted.
|
|
||||||
- `fraction`
|
|
||||||
- `commenter`: The person who interrupted the speech.
|
|
||||||
- `comment`: The content of the comment.
|
|
||||||
|
|
||||||
###applause
|
|
||||||
|
|
||||||
The logical table shows which party applauded for which speaker with explicit speech and which did not.
|
|
||||||
|
|
||||||
structure: `speech_id`, `on_speaker`, `CDU_CSU`, `SPD`, `FDP`, `DIE_LINKE`, `BUENDNIS_90_DIE_GRUENEN`, `AfD`
|
|
||||||
|
|
||||||
|
|
||||||
# Analysis
|
|
||||||
|
|
||||||
analysis.R provides some functions to analyze the "Plenarprotokolle" and to create plots.
|
|
||||||
|
|
||||||
In the vignettes you can find different analyses of the protocols, for example:
|
|
||||||
|
|
||||||
- "Who talks the most?"
|
|
||||||
- "Which party gives the most speeches?"
|
|
||||||
- "Which party comments the most on which parties?"
|
|
||||||
- "When are which topics discussed the most?"
|
|
||||||
- ...
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+108989
File diff suppressed because it is too large
Load Diff
@@ -4,15 +4,30 @@
|
|||||||
\name{hateimparlament-package}
|
\name{hateimparlament-package}
|
||||||
\alias{hateimparlament}
|
\alias{hateimparlament}
|
||||||
\alias{hateimparlament-package}
|
\alias{hateimparlament-package}
|
||||||
\title{hateimparlament: Protocolanalysis of German Bundestag}
|
\title{hateimparlament: Recordanalysis Of Bundestag}
|
||||||
\description{
|
\description{
|
||||||
Downloads, parses and analyses protocols of the current German parliament (Bundestag).
|
Downloads, parses and analyses parliamentary records of the 19th legislative
|
||||||
|
period of the German parliament (Bundestag).
|
||||||
}
|
}
|
||||||
\details{
|
\details{
|
||||||
hateimparlament ist ein großartiges Paket!
|
hateimparlament ist ein großartiges Paket!
|
||||||
|
}
|
||||||
|
\seealso{
|
||||||
|
Useful links:
|
||||||
|
\itemize{
|
||||||
|
\item \url{https://git.flavigny.de/christian/hateimparlament}
|
||||||
|
\item Report bugs at \url{https://git.flavigny.de/christian/hateimparlament/issues}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
\author{
|
\author{
|
||||||
\strong{Maintainer}: First Last \email{first.last@example.com} (\href{https://orcid.org/YOUR-ORCID-ID}{ORCID})
|
\strong{Maintainer}: Christian Merten \email{christian@merten.dev}
|
||||||
|
|
||||||
|
Authors:
|
||||||
|
\itemize{
|
||||||
|
\item Leon Burgard
|
||||||
|
\item Josua Kugler
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
\keyword{internal}
|
\keyword{internal}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: "explicittopic"
|
title: "Analysis of covered topics"
|
||||||
output: rmarkdown::html_vignette
|
output: rmarkdown::html_vignette
|
||||||
vignette: >
|
vignette: >
|
||||||
%\VignetteIndexEntry{explicittopic}
|
%\VignetteIndexEntry{Analysis of covered topics}
|
||||||
%\VignetteEngine{knitr::rmarkdown}
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
%\VignetteEncoding{UTF-8}
|
%\VignetteEncoding{UTF-8}
|
||||||
---
|
---
|
||||||
@@ -34,9 +34,10 @@ read_all("../inst/records/") %>% repair() -> res
|
|||||||
```
|
```
|
||||||
We also used `repair` to fix a bunch of formatting issues in the records.
|
We also used `repair` to fix a bunch of formatting issues in the records.
|
||||||
|
|
||||||
For development purposes, we load the tables from csv files.
|
For development purposes, we only fetch records if they are not already
|
||||||
|
stored as csv files:
|
||||||
```{r}
|
```{r}
|
||||||
res <- read_from_csv('../inst/csv/')
|
res <- read_from_csv_or_fetch('../inst/')
|
||||||
```
|
```
|
||||||
|
|
||||||
## Analysis
|
## Analysis
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: "genderequality"
|
title: "Differences in gender"
|
||||||
output: rmarkdown::html_vignette
|
output: rmarkdown::html_vignette
|
||||||
vignette: >
|
vignette: >
|
||||||
%\VignetteIndexEntry{genderequality}
|
%\VignetteIndexEntry{Differences in gender}
|
||||||
%\VignetteEngine{knitr::rmarkdown}
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
%\VignetteEncoding{UTF-8}
|
%\VignetteEncoding{UTF-8}
|
||||||
---
|
---
|
||||||
@@ -20,7 +20,7 @@ library(dplyr)
|
|||||||
library(ggplot2)
|
library(ggplot2)
|
||||||
library(stringr)
|
library(stringr)
|
||||||
library(tidyr)
|
library(tidyr)
|
||||||
library(rvest)
|
library(xml2)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Preparation of data
|
## Preparation of data
|
||||||
@@ -33,13 +33,15 @@ Second, those `.xml` files, need to be parsed into `R` `tibbles`. This is accomp
|
|||||||
```r
|
```r
|
||||||
read_all("../records/") %>% repair() -> res
|
read_all("../records/") %>% repair() -> res
|
||||||
```
|
```
|
||||||
We also used `repair` to fix a bunch of formatting issues in the records and unpacked
|
We also used `repair` to fix a bunch of formatting issues in the records.
|
||||||
the result into more descriptive variables.
|
|
||||||
|
|
||||||
For development purposes, we load the tables from csv files.
|
For development purposes, we only fetch records if they are not already
|
||||||
|
stored as csv files:
|
||||||
```{r}
|
```{r}
|
||||||
res <- read_from_csv('../inst/csv/')
|
res <- read_from_csv_or_fetch('../inst/')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
and unpack our tibbles
|
and unpack our tibbles
|
||||||
```{r}
|
```{r}
|
||||||
comments <- res$comments
|
comments <- res$comments
|
||||||
@@ -48,53 +50,33 @@ speaker <- res$speaker
|
|||||||
talks <- res$talks
|
talks <- res$talks
|
||||||
```
|
```
|
||||||
|
|
||||||
Bevor we can do our analysis, we have to assign a gender to our politicans.
|
Bevor we can do our analysis, we have to assign a gender to our politicans. We do this
|
||||||
|
by reading the gender from the master data of all members of parliament, which is
|
||||||
|
fetched from bundestag.de.
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
extract_href <- function(sel, html) {
|
xml_get <- function(node, name) {
|
||||||
html %>%
|
res <- xml_text(xml_find_all(node, name))
|
||||||
html_node(sel) %>%
|
if (length(res) == 0) NA_character_
|
||||||
html_attr("href")
|
else res
|
||||||
}
|
}
|
||||||
|
|
||||||
first_content_p_text <- function(url) {
|
x <- read_xml("../inst/masterdata.xml")
|
||||||
res <- NA
|
mdbs <- xml_find_all(x, "MDB")
|
||||||
i <- 1
|
|
||||||
while(is.na(res)) {
|
ids <- c()
|
||||||
read_html(url) %>%
|
genders <- c()
|
||||||
html_node(str_glue("#mw-content-text > div.mw-parser-output > p:nth-child({i})")) %>%
|
for (mdb in mdbs) {
|
||||||
html_text() -> res
|
xml_get(mdb, "ID") -> mdb_id
|
||||||
i <- i + 1
|
xml_find_first(mdb, "BIOGRAFISCHE_ANGABEN") %>%
|
||||||
}
|
xml_get("GESCHLECHT") ->
|
||||||
res
|
mdb_gender
|
||||||
|
ids <- c(ids, mdb_id)
|
||||||
|
genders <- c(genders, if (mdb_gender == "männlich") "male" else "female")
|
||||||
}
|
}
|
||||||
|
|
||||||
abgeordneten_list_html <- read_html(
|
gender <- tibble(id = ids, gender = genders)
|
||||||
"https://de.wikipedia.org/wiki/Liste_der_Mitglieder_des_Deutschen_Bundestages_(19._Wahlperiode)")
|
speaker_with_gender <- left_join(res$speaker, gender)
|
||||||
|
|
||||||
selectors <- str_glue("#mw-content-text > div.mw-parser-output > table:nth-child(20) > tbody > tr:nth-child({2:709}) > td:nth-child(2) > a")
|
|
||||||
link_part2 <- sapply(selectors, extract_href, abgeordneten_list_html)
|
|
||||||
link <- str_c("https://de.wikipedia.org", link_part2)
|
|
||||||
|
|
||||||
text <- sapply(link, first_content_p_text)
|
|
||||||
text %>%
|
|
||||||
str_extract(" ist ein.") %>%
|
|
||||||
str_replace(" ist eine", "female") %>%
|
|
||||||
str_replace(" ist ein ", "male") ->
|
|
||||||
gender
|
|
||||||
|
|
||||||
text %>%
|
|
||||||
str_extract("^([:upper:]?[:lower:]+[\\s\\-]?)*") %>%
|
|
||||||
str_trim() ->
|
|
||||||
names
|
|
||||||
|
|
||||||
gender <- tibble(speaker = names,
|
|
||||||
gender = gender)
|
|
||||||
|
|
||||||
speaker %>%
|
|
||||||
unite("speaker", vorname, nachname, sep = " ") %>%
|
|
||||||
right_join(gender, by = "speaker") ->
|
|
||||||
speaker_with_gender
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Analyse
|
## Analyse
|
||||||
@@ -161,7 +143,7 @@ speeches %>%
|
|||||||
|
|
||||||
|
|
||||||
party_order <- factor(c("Fraktionslos", "AfD&Fraktionslos",
|
party_order <- factor(c("Fraktionslos", "AfD&Fraktionslos",
|
||||||
"DIE LINKE", "BÜNDNIS 90 / DIE GRÜNEN", "SPD", "CDU/CSU",
|
"DIE LINKE", "BÜNDNIS 90/DIE GRÜNEN", "SPD", "CDU/CSU",
|
||||||
"FDP", "AfD", NA_character_))
|
"FDP", "AfD", NA_character_))
|
||||||
|
|
||||||
speech_distribution %>%
|
speech_distribution %>%
|
||||||
@@ -179,9 +161,8 @@ speeches %>%
|
|||||||
summarize(n = n()) %>%
|
summarize(n = n()) %>%
|
||||||
ungroup() %>%
|
ungroup() %>%
|
||||||
arrange(-n) %>%
|
arrange(-n) %>%
|
||||||
left_join(speaker, by=c("speaker" = "id")) %>%
|
join_speaker(res) %>%
|
||||||
unite(name, vorname, nachname, sep = " ") %>%
|
left_join(gender, by=c("speaker"="id")) %>%
|
||||||
inner_join(gender, by=c("name"= "speaker")) %>%
|
|
||||||
group_by(gender) %>%
|
group_by(gender) %>%
|
||||||
summarise(absolute=sum(n)) %>%
|
summarise(absolute=sum(n)) %>%
|
||||||
filter(gender %in% c("female", "male")) %>%
|
filter(gender %in% c("female", "male")) %>%
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: "generalquestions"
|
title: "General questions"
|
||||||
output: rmarkdown::html_vignette
|
output: rmarkdown::html_vignette
|
||||||
vignette: >
|
vignette: >
|
||||||
%\VignetteIndexEntry{generalquestions}
|
%\VignetteIndexEntry{General questions}
|
||||||
%\VignetteEngine{knitr::rmarkdown}
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
%\VignetteEncoding{UTF-8}
|
%\VignetteEncoding{UTF-8}
|
||||||
---
|
---
|
||||||
@@ -34,9 +34,10 @@ read_all("../inst/records/") %>% repair() -> res
|
|||||||
```
|
```
|
||||||
We also used `repair` to fix a bunch of formatting issues in the records.
|
We also used `repair` to fix a bunch of formatting issues in the records.
|
||||||
|
|
||||||
For development purposes, we load the tables from csv files.
|
For development purposes, we only fetch records if they are not already
|
||||||
|
stored as csv files:
|
||||||
```{r}
|
```{r}
|
||||||
res <- read_from_csv('../inst/csv/')
|
res <- read_from_csv_or_fetch('../inst/')
|
||||||
```
|
```
|
||||||
|
|
||||||
## Analysis
|
## Analysis
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ talks <- res$talks
|
|||||||
We also used `repair` to fix a bunch of formatting issues in the records and unpacked
|
We also used `repair` to fix a bunch of formatting issues in the records and unpacked
|
||||||
the result into more descriptive variables.
|
the result into more descriptive variables.
|
||||||
|
|
||||||
For development purposes, we load the tables from csv files.
|
For development purposes, we only fetch records if they are not already
|
||||||
|
stored as csv files:
|
||||||
```{r}
|
```{r}
|
||||||
tables <- read_from_csv('../inst/csv/')
|
tables <- read_from_csv_or_fetch('../inst/')
|
||||||
|
|
||||||
comments <- tables$comments
|
comments <- tables$comments
|
||||||
speeches <- tables$speeches
|
speeches <- tables$speeches
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: "interaction"
|
title: "Interaction between fractions"
|
||||||
output: rmarkdown::html_vignette
|
output: rmarkdown::html_vignette
|
||||||
vignette: >
|
vignette: >
|
||||||
%\VignetteIndexEntry{interaction}
|
%\VignetteIndexEntry{Interaction between fractions}
|
||||||
%\VignetteEngine{knitr::rmarkdown}
|
%\VignetteEngine{knitr::rmarkdown}
|
||||||
%\VignetteEncoding{UTF-8}
|
%\VignetteEncoding{UTF-8}
|
||||||
---
|
---
|
||||||
@@ -34,9 +34,10 @@ read_all("../inst/records/") %>% repair() -> res
|
|||||||
```
|
```
|
||||||
We also used `repair` to fix a bunch of formatting issues in the records.
|
We also used `repair` to fix a bunch of formatting issues in the records.
|
||||||
|
|
||||||
For development purposes, we load the tables from csv files.
|
For development purposes, we only fetch records if they are not already
|
||||||
|
stored as csv files:
|
||||||
```{r}
|
```{r}
|
||||||
res <- read_from_csv('../inst/csv/')
|
res <- read_from_csv_or_fetch('../inst/')
|
||||||
```
|
```
|
||||||
|
|
||||||
## Analysis
|
## Analysis
|
||||||
|
|||||||
Reference in New Issue
Block a user