Eine kleine Essensumfrage

In diesem Beitrag geht es um ein kleines Seitenprojekt: Eine (nicht-repräsentative) Essensumfrage um einen Eindruck zu bekommen, welches Essen wie (un-)beliebt ist, ob Essvorlieben mit Reisezielen korrelieren, ob es verschiedene “Esstypen” gibt und vieles mehr.

Die Idee

Während des Mittags reden wir oft über Essen. Über verschiedene Geschmäcker, wie (un-)beliebt bestimmte Essen sind und ob es vielleicht verschiedene Esstypen gibt (Leute, die Lakritze mögen, essen ungern XY?). Um etwas Licht in diese Fragen zu bringen, weil wir keine zugänglichen Studien finden konnten, und mit allen Werkzeugen der Web-Entwicklung und Statistik im Handgepäck, entschlossen wir uns für ein Seitenprojekt.

Nun präsentieren wir eine kleine Essensumfrage! Da wir keine repräsentative Stichprobe auswählen, lassen sich die Ergebnisse nicht verallgemeinern. Die Ergebnisse sagen nur etwas über die teilnehmenden Personen aus, nicht über Deutschland, sicher nicht über die ganze Welt. Wir hoffen, dass die Ergebnisse uns und dir trotzdem Freude bereiten und einige interessante Zusammenhänge liefern.

Weitere Infos

Nachdem du dich durch drei mittelkurze Seiten mit Fragen geklickt hast, gibt es außerdem einige vorläufige Ergebnisse zu sehen und wie die Anderen im Vergleich zu dir geantwortet haben. Außerdem gilt selbstverständlich:

  • Alle Ergebnisse sind vollständig anonym und werden nicht kommerziell genutzt.
  • Über den Verlauf unserer kleinen Umfrage werden wir hier in diesem Blog-Beitrag informieren.
  • Wenn du die Umfrage weitergeben möchtest, bist du herzlich dazu eingeladen.

Wir freuen uns über Kommentare und Fragen. Viel Spaß!

dqsample: Eine faire Alternative zu ‚base::sample‘

Das Erzeugen von zufälligen Stichproben eines Datensatzes wird in der Statistik oder Data Science oft angewendet. Für diese Aufgabe gibt es in R die Funktion base::sample. Leider ist der dabei verwendete Algorithmus nicht vollständig fair. Dies wurde zuletzt auf R-devel diskutiert, was auch die Motivation für das dqsample Paket darstellt. Derzeit ist dqsample nicht auf CRAN, kann aber über drat installiert werden:

Beispiel

Wählt man viele Zahlen zufällig aus, so sollten die Dichten der geraden und ungerade Zahlen in etwa gleich und konstant sein. Mit base::sample ist dies jedoch nicht er Fall:

plot of chunk base

Oder mit verändertem Parameter:

plot of chunk base-oszi

Dieses spezielle Beispiel stammt von Duncan Murdoch.

Daniel Lemire (2018, <arXiv:1805.1094>) hat einen alternativen Algorithmus vorgeschlagen, der in dqsample verwendet wird. Mit diesem Algorithmus gibt es keine Asymmetrie zwischen geraden und ungeraden Zahlen:

plot of chunk dqsample

Ursachenforschung

Intern benötigt die base::sample() Funktion zufällige ganze Zahlen die gleichmäßig in dem halb-offenen Bereich [0, n) verteilt sind.Um diese zu erzeugen, verwendet R zufällige Gleitkommazahlen aus [0, 1), multipliziert mit n und schneidet den Nachkommateil ab. Mit reellen Zahlen im mathematischen Sinn wäre das korrekt. Aber das ist hier nicht der Fall.

Standardmäßig verwendet R einen 32 bit Mersenne-Twister zum Erzeugen von Zufallszahlen. Dieser erzeugt ganze Zahlen aus [0, 2^32), die durch 2^32geteilt werden um Gleitkommazahlen aus [0, 1) zu erhalten.Wenn wir das oben beschriebene Verfahren invertieren, so können wir sehen wie viele mögliche Zufallszahlen zu einem Ergebnis gehören.  Mit sample(6, 10, replace = TRUE) kann man zum Beispiel den Wurf von zehn Würfeln simulieren. Da 2^32 kein Vielfaches von sechs ist, kann die Verteilung aber nicht gleichverteilt sein:

Eins und vier haben eine minimal geringere Wahrscheinlichkeit als die übrigen Zahlen. Dieser Effekt steigt mit der Größe des Datensatzes, aus dem gewählt wird. Verwenden wir das oben definierte m so können wir sehen, woher die ungleiche Verteilung gerader und ungerader Zahlen herkommt:

Während jeweils zwei Zahlen auf eine der ungeraden Zahlen abgebildet werden, sind es drei Zahlen für jede gerade Zahl. Dieses Muster verschiebt sich bei der Hälfte der möglichen Ergebnisse, was das erste Bild oben erklärt. Das Muster verschiebt sich öfter, wenn man sich von m entfernt, was die Oszillationen im zweiten Bild erklärt. Irgendwann werden die Oszillationen zu schnell, um sie in der Dichte sehen zu können. Das bedeutet aber nicht, dass die Verteilung fair ist. Für m - 2^20verschiebt sich das Muster beispielsweise zwischen 982 und 983:

Vorher sind gerade Zahlen wahrscheinlicher als ungerade Zahlen. Danach ist es umgekehrt.

Zusammenfassung

Der von base::sample verwendet Algorithmus ist nicht fair, was zusammen mit großen Datenmengen einen merkbaren Effekt haben kann. Das dqsample Paket stellt für die wichtigsten Anwendungsfälle einen fairen Algorithmus bereit. Es kann als direkter Ersatz für base::sample verwendet werden.

Der R style guide von daqana ist online

Er ist eine Weiterentwicklung des tidyverse style guides (http://style.tidyverse.org/).

Was ist eigentlich ein style guide und wozu ist er gut?

Ein style guide – zu deutsch: Gestaltungsrichtlinie – gibt Programmierern Regeln vor, wie sie ihren Code gestalten sollen. Um zu funktionieren, muß der Code einer bestimmten Grammatik und Interpunktion folgen. Hierbei gibt es, wie auch in der normalen Sprache, gewisse Freiheiten.

In einem style guide werden Empfehlungen ausgesprochen, die diese Freiheiten mit dem Ziel der Vereinheitlichung einschränken. Teilweise sind die Empfehlungen für eine bestimmte Variante relativ willkürlich. Mitunter ist eine Variante aber in Bezug auf verschiedene Qualitätskriterien auch besser geeignet als eine andere. Diese Qualitätskriterien können etwa die Lesbarkeit und Verständlichkeit, aber auch die Leistungsfähigkeit (Schnelligkeit, Skalierbarkeit) des Codes betreffen.

Die Vorteile, die sich ergeben, wenn Programmierer einem gemeinsamen style guide folgen, sind also zum einen die Einhaltung von Qualitätsstandards, zum anderen ein einfaches Sich-zurecht-Finden im Code, auch wenn er von anderen oder gemeinsam geschrieben wird, und damit nicht zuletzt eine bessere Wartbarkeit und Erweiterbarkeit des Codes.

Warum wurde der tidyverse style guide als Vorlage benutzt und warum wurde er nicht 1:1 übernommen?

Das tidyverse umfaßt eine Menge Pakete, von denen viele es erleichtern, die Qualität der eigenen Analysen zu erhöhen, und die schnell sehr populär wurden. Grundlage für den tidyverse style guide ist neben dem „Google R style guide“ (https://google.github.io/styleguide/Rguide.xml) offensichtlich auch das ausgezeichnete Buch von Hadley Wickham zur Paketentwicklung („R packages“ http://r-pkgs.had.co.nz/).

Der tidyverse style guide umfaßt neben einem klassischen Kapitel zur Syntax auch Hinweise zur empfohlenen Praxis bei der Paketentwicklung. Diese breite Auffassung, wie auch die Expertise und die weite Verbreitung waren für uns die Gründe, den tidyverse style guide als Richtlinie für unsere tägliche Arbeit zu prüfen.

Tatsächlich stimmt der daqana style guide zu sehr großen Teilen mit dem tidyverse style guide überein. An einzelnen Stellen haben wir Erklärungen für bestimmte Entscheidungen hinzugefügt, insbesondere wo wir doch Änderungen vorgenommen haben. Dem Kapitel zur Pipe wurde ein Absatz vorangestellt, da ihre Nutzung eher kritisch gesehen wird. Ein kurzes Kapitel zu Unit Tests wurde eingefügt.

Der sichtbarste Unterschied ist, daß gute und schlechte Beispiele farblich hervorgehoben wurden, was unserer Auffassung nach die Nutzerfreundlichkeit erhöht. Wir haben uns außerdem bemüht, direkt an den entsprechenden Stellen Hinweise auf passende lintr-Funktionen (https://github.com/jimhester/lintr) anzugeben und stellen diese in der Datei daqana_linters.R zur Verfügung, so daß eine direkte Einbindung dieser linter im entsprechenden RStudio Add-In möglich ist.

Wir sehen den style guide nicht als abgeschlossenes Werk an, werden prüfen, wie er sich in unserem Alltag bewährt und planen für die Zukunft unter anderem eine Zusammenstellung von passenden styler-Funktionen  (https://github.com/r-lib/styler) analog zu den linters.

Hier ist also die erste Version des daqana R style guides. Viel Freude damit! https://www.daqana.org/dqstyle-r/

tikzDevice hat ein neues zu Hause

Im Februar diesen Jahres wurde das tikzDevice Paket auf CRAN auf ORPHANED gestellt. In der Folge suchten Kirill Müller und Yihui Xie eine neuen Maintainer. Als wir das einige Zeit später lasen, beschlossen wir uns hier einzubringen. Nach einem kurzen E-Mail-Dialog mit Yihui Xie wurde das GitHub Repository auf unsere Organization übertragen: https://github.com/daqana/tikzDevice. Derweil haben wir die bestehenden Warnungen aus den CRAN checks behoben und Version 0.12 hochgeladen.

Was kann man mit tikzDevice tun? es is ein graphics device vergleichbar zu pdf() oder png(). Aber an Stelle einer Bilddatei, die in einen Report als externe Graphik eingefügt werden kann, erzeugt es Dateien im TikZ format durch die LaTeX die Graphiken erstellt. Das ermöglicht konsistente Schriften für Text und Graphiken sowie die Verwendung von TeXs Fähigkeiten zur Darstellung mathematischer Formeln. Die PDF-Vignette enthält viele Beispiele.

Man kann es sogar in einem R-Markdown Dokument nutzen. Ein Dokument mit

im YAML Kopf und

in einem setup Block wird für Text und Graphiken die gleiche Schrift nutzen, wenn letztere mit dev = "tikz" erzeugt werden. In diesem Beispiel Palatino mit Minuskelziffern:

Palatino mit Minuskelziffern

 

Shiny-Apps mit testthat (unit-) testen

In diesem Blog-Beitrag wird erklärt, wie man eine Shiny-App mithilfe der Pakete shinytest und testthat testen kann. Grundlegende Vorkenntnisse über Shiny-Apps und das Prinzip von Unit-Tests mit dem Paket testthat sind nützlich, werden hier aber nicht vorausgesetzt.

Beispiel einer Shiny-App

Für den hier vorgestellten Test sind die Pakete shiny (aktuell: 1.1.0), testthat (1.3.0) und shinytest (2.0.0) erforderlich. Falls nötig können sie bequem mit install.packages() installiert werden.

Unten ist ein minimales Beispiel einer Shiny-App (app.R), die getestet werden soll. Die App hat nur einen einzigen numerischen Input und einen Text-Output. Die eingegebene Zahl n wird quadriert und das Ergebnis wird als Text angezeigt.

Und so sieht die App aus:

Was ist shinytest?

Das Paket shinytest ermöglicht das automatische Testen einer Shiny-App. Dabei wird sowohl das “Aussehen” der App, sowie ihr “interner” Zustand zu einem bestimmten Zeitpunkt im Programmablauf untersucht. Mithilfe eines interaktiven User-Interfaces lassen sich Snapshots (genauer gesagt Referenz-Snapshots) sowie eine Test-Datei erstellen. Die Test-Datei beinhaltet den Code, der für spätere Wiederherstellung der Snapshots erforderlich ist. Bei jedem weiteren Test werden neue Snapshots erstellt und mit den Referenz-Snapshots verglichen, um unerwartetes Verhalten der Shiny-App automatisch zu detektieren. Mehr zu dem normalen Workflow mit shinytest ist hier zu finden. In diesem Blog-Beitrag wird allerdings ein anderer Umgang mit dem Testen beschrieben; Nämlich das gemeinsame Testen mittels shinytest und testtthat [*].

[*] Nicht hier besprochen wird die Funktion expect_pass (vgl. ?expect_pass), die einfach alle shinytest-Snapshots vergleicht und über Abweichungen informiert. Das erlaubt zwar schnelle Vergleiche, aber ist weniger detailliert und spezifisch als der hier vorgestellte Ansatz.

Shiny-Apps mit shinytest & testthat testen

shinytest verfügt über die Klasse ShinyDriver (vgl. ?ShinyDriver), die beim Erstellen eines neuen Objekts die Shiny-App in einer neuen R-Session sowie eine Instanz von PhantomJS öffnet und diese automatisch mit der Shiny-App verbindet. PhantomJS ist ein Headless Webbrowser, der durch JavaScript bedient werden kann. Das ShinyDriver-Objekt ist mit verschiedenen Methoden ausgerüstet, die vor allem das Auslesen bzw. Eingeben von Werten für verschiedene Variablen in der shiny-App ermöglichen. Man kann also den Input-Variablen beliebige Werte gezielt, “manuell” (ohne das übliche User-Interface der Shiny-App) zuweisen und dann die Ausgabe-Variablen auslesen.

Beispiel eines Tests

In folgendem Test wird die Variable num_input auf 30 gesetzt und dann getestet, ob die Variable text_out zum String “Das Quadrat der Zahl n lautet: n² = 900” wird. Mehr zum Testen mit testthat ist hier zu finden.

Mit den Erwartungsfunktionen des Pakets testthat ist es also bequem möglich, die Funktionalitäten der Shiny-App zu testen. Ein Vorteil dabei ist auch, dass beim Aufrufen von devtools::test() sowohl die Tests der Shiny-App als auch die weiteren Unit-Tests mitberücksichtigt werden.

Tiefere Einsichten – Exportierte Variablen und HTML-Widgets

Innerhalb der server-Funktion von Shiny kann man zudem neue Variablen (außer der üblichen Inputs und Outputs) extra definieren. Diese sind dann von shinytest-Seite “sichtbar” und erlauben eine detailliertere Untersuchung der App-Abläufe. Als Beispiel für die oben gezeigte Shiny-App kann man die Liste aller eingegebenen Zahlen n speichern und als Variable inputs_list exportieren (bitte siehe den Code unten).

Für verschiedene HTML-Widgets bietet sich die Methode findElement mit der XPath zu verwenden app$findElement(xpath = "Hier das XPATH"). Wenn man beispielsweise Benachrichtigungen mit der Funktion showNotification() in der Shiny-App zeigt, kann man sie mit xpath = "//*[@id=\"shiny-notification-panel\"]" identifizieren und entsprechend testen.

Im Folgenden wird gezeigt, wie man in der Shiny-App eine Variable exportiert und Benachrichtigungen mittels showNotification() Benachrichtigungen darstellt:

Ein Test kann dann beispielsweise wie folgt aussehen: