Hier findet sich der gesamte Inhalt des Handbuchs zum Durchsuchen. Diese Seite wird nur unregelmäßig geupdated. Aktuelle Skripte finden sich auf der
Rclick Hauptseite!
Tipp: mit Pfeiltaste links/rechts kann horizontal gescrollt werden.
Syntax highlighting mit [*sourcecode language=“r“ gutter=“false“], dann den Codeblock, dann [*/sourcecode] (natürlich ohne Sternchen *), wie von WordPress vorgeschlagen.
# Komplettes Handbuch zum Durchsuchen. Im TinnR: STRG+F, weiter mit F3 # Stand: 2016-07-12 07:32:12 -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 1: Grundlagen ###################################################### # 1.1 Hilfe aufrufen # 1.2 Rechenoperatoren # 1.3 Zuordnungen # 1.4 Objektarten # 1.5 Grund-Datentypen (Übersicht) # 1.6 Objekttypen (Übersicht) # Kommentare mit einem Kreuz (#) beginnen, werden von R nicht ausgewertet. # Leerzeichen und -zeilen werden nicht ausgewertet; sie dienen der Übersicht. # Mehrere Befehle in einer Zeile können mit ; voneinander getrennt werden. # schon früh sollte man sich angewöhnen, bequem zu programmieren: browseURL("http://RclickHandbuch.wordpress.com/install-r/tinn-r/") # Besonders: TinnR Options > Shortcuts sowie Return focus to editor # STRG + F : Find. Suche nach Wörtern. Weiter mit F3 # STRG + 9 schreibt Klammern und setzt den Cursor in deren Mitte # Wer gerne mit VideoTutorials lernt, könnte hier schauen: browseURL("https://www.youtube.com/user/Tutorlol") # Ansonsten sei hier nochmals auf die Literaturliste im Anhang verwiesen... # 1.1 Hilfe aufrufen ----------------------------------------------------------- # ? Befehl() oder help.search("Befehl") ?mean() # Befehlsteil in Klammern wird ignoriert help.search("mean") # kürzer: ??mean help.start() # HTML Hilfe (Automatischer Start des Browsers) # am schnellsten: cursor auf Befehl im TinnR setzen, F1 drücken # bei Befehlen mit Punkt: den ganzen Befehl zuerst markieren. help.search("Kolmogorov Smirnov") ?ks.test # 1.2 Rechenoperatoren --------------------------------------------------------- 7+11 3*9/5 3^2 16:21 # ganze Zahlen (Integer) von 16 bis 21 (als Vektor) sqrt(81) # Wurzel (gleiches Ergebnis bei 81^0.5 ) abs(-12) # absolutwert (Betrag) sin(2.4*pi) # ACHTUNG: keine Kommas (,) als Dezimaltrennzeichen verwenden! exp(3) # e^3 log(100) # log(x) ist im R ln(x) log10(100) # log10(x) ist der Logarithmus mit Basis 10 factorial(5) # 5! (5 Fakultät) 0.0002 # xx e yy bedeutet: xx * 10 ^ yy (Exponentialschreibweise, 3e5 # auch Scientific Notation genannt) 1.9343E+03 + 2 print(pi, digits=16) # print für eine benutzerdefinierte Ausgabe options("digits"=16) # Ab jetzt jede Ausgabe mit 16 Nachkommastellen sin(0.8) options("digits"=7) # wieder zurück auf die DEFAULT = Standard Einstellung -1/0 ; 0/0 ; 1/0 # Inf = Infinity = unendlich; NaN = Not a number # 1.3 Zuordnungen (Englisch: Assignment) -------------------------------------- # Werte, Zeichenketten, Aussagen... als Variablen speichern (Objekten zuordnen) # R unterscheidet Großschreibung! probe1 <- 17.5 # Punkt als Dezimaltrennzeichen verwenden # Anzeigen der zugeordneten Daten probe1 # Das ist jetzt ein Objekt im Workspace, nur in dieser R-Sitzung. probe1 + 12 # Jetzt kann damit auch weitergerechnet werden. p2 <- 1 > 2 # Ist 1 größer als 2? Ergebnis wird als p2 gespeichert. p2 # Symbole möglichst kurz aber wiedererkennbar wählen p3 <- sin (5) # Werte in Radiant (pi = 180°) x = alpha*pi/180° sin(45*pi/180) # sinus von 45° p4 <- "ein Text" # Anführungsstriche nicht vergessen p4 p5 <- TRUE # oder kürzer: p5 <- T (bzw F für FALSE) sqrt(9030) -> p6 # Zuordnungen in beiden Richtungen möglich, aber "->" # sollte vermieden werden, da es sehr ungewöhnlich, daher schlecht lesbar ist. p7 = 7:15 # Zuordnen mit "=" ist möglich, aber ungünstig: p7 # http://r.789695.n4.nabble.com/assign-td2291499.html # Funktioniert als Zuordnung nur direkt im Skript, nicht in Funktionen. # Eine Zuordnung zu bereits belegten Namen und Funktionen ist NICHT sinnvoll! # Dazu gehören zB c, t, data, F, T, sin, ls. Data ist OK, weil großgeschrieben # Außer bei FALSE, NA, etc (?reserved) ist es möglich, aber nicht empfehlenswert # Wird die Zuordnung in Klammern gesetzt, wird sie gleichzeitig aufgerufen (p8 <- 2854) # Das ist recht ungewöhnlich, man sollte es daher meiden. ?"<-" # ruft die Hilfe zur Zuordnung auf # 1.4 Objektarten: ------------------------------------------------------------- # Abfragen des Datentyps: mode(probe1) # numeric - Zahl str(probe1) # STRucture # num mode(p4) # character - Zeichenkette (Buchchstaben) mode(p7) # numeric str(p7) # int - Integer, ganze Zahl, Unterform von num (-> 1.5) # Abfrage, welche Zuordnungen bestehen ls() ls.str() # Zuordnungen löschen (Objekt aus dem Workspace löschen) rm(p7) p7 # Fehler: Objekt 'p7' nicht gefunden rm(list=ls()) # entfernt alle Objekte, räumt also auf. Im TinnR F11 drücken. p9 <- "1.3" # passiert manchmal beim Einlesen von Dateien (Kap 3) p9 2*p9 # geht nicht as.numeric(p9) # jetzt ist aus dem Text eine Zahl geworden 2*as.numeric(p9) # und kann damit entsprechend gerechnet werden p9 # das Objekt selbst wurde dabei nicht verändert is.numeric(p9) # is.___ fragt ab, ob ein Objekt ein bestimmter Datentyp ist as.character(6:8) # as.___ erzwingt eine Objektart-änderung. as.numeric(TRUE) as.logical(0:1) # FALSE = 0, TRUE = 1 # 1.5 Grund-Datentypen: -------------------------------------------------------- ?numeric # Zahlen ? integer # ganze Zahlen / werden von mode als numeric ausgegeben, ? double # KommaZahlen, NaN, Inf / str unterscheidet genauer ?logical # Wahrheitswerte: T=TRUE, F=FALSE ?character # Zeichenketten wie "Ueberschrift" ?complex # Komplexe Zahlen wie 7+3i ?factor # Kategorie, kategorielle Variablen # 1.6 Objekttypen -------------------------------------------------------------- ?vector # Vektor ?data.frame # gängigste Form einer Tabelle: verschiedene Datentypen in Spalten ?matrix # Jedes Element gleichen Datentyps! zweidimensionaler array ?array # mehrdimensionale Matrix (zB für räumliche Daten über Zeit) ?list # mehrere Modi in einem Objekt möglich, Indzierung mit [[n]] ?ts # Zeitreihe # und einige mehr, die hier noch nicht wichtig sind. mode(p9) # Daten- oder Objekt-typ, einiges ist dabei zusammengefasst typeof(p9) # R-intern, vom Nutzer fast nie verwendet, genauer als mode str(p9) # Gesamtstruktur vor allem komplizierter Objekte class(p9) # Objekttyp class(7:8) # zeigt bei Vektoren den Datentyp an is.vector(7:8)# für Abfragen, ob ein Objekttyp "vector" ist. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 2: Vektoren und Tabellen ########################################### # 2.1 Vektoren erstellen + Indizieren # 2.2 rep, seq, : # 2.3 Vektoren mit character # 2.4 Basic Statistics # 2.5 oft verwendete Operatoren # 2.6 Tabellen # 2.7 Tabellenindizierung # 2.8 Tabellen zusammenführen # 2.9 Zeilen und Spaltennamen # 2.10 Matrizen # 2.1 Vektoren erstellen: c + Indizieren: [] ----------------------------------- # Vektoren erstellen, Elemente durch Kommas trennen vekt1 <- c(1 , -2 , 3, 7:11) # c steht für combine oder concatenate vekt1 mode(vekt1) # Auf Vektorelement zugreifen mit eckigen Klammern vekt1 [5] vekt1[5:6] # Vektor mit einer entfernten Stelle erstellen/anzeigen: [-Element] vekt2 <- vekt1 [-5] vekt2 # Manipulation einzelner Elemente vekt2[5] <- 28 vekt2 # Hinzufügen von Elementen. Zwischenkomponenten werden als NA eingefügt. vekt2[10] <- -13 vekt2 vekt2[7]*3 # Zeigt nur das Ergebnis einer Berechnung an, ändert nicht den Vektor vekt2 ( k <- c(2,4,5) ) # Zuordnung in Klammern zeigt entstehendes Objekt gleich an vekt2[k] # zugegriffen wird immer vektoriell # 2.2 rep, seq, : -------------------------------------------------------------- # Mehrfaches Wiederholen einer Zahl im Vektor: rep(Zahl, AnzahlWiederholungen) vekt3 <- rep(2, 10) # repeat vekt3 # Sequenz: seq(von, bis, Schrittweite) ( vekt4 <- seq(1, 5, 0.5) ) # Sequenz: seq(von, bis, len = Anzahl Elemente) ( vekt5 <- seq(1, 3, len=15) ) # len kurz für length.out seq(7, 6, -1/3) # Bei absteigenden Sequenzen negativen "by"-wert nutzen! 8:13 # Ganze Zahlen (integer) von 8 bis 13 -3:6 # folglich beim Entfernen beim Indizieren Klammern verwenden: vekt1 vekt1[-(3:6)] # und nicht etwa so: vekt1[-3:6] # Fehler: nur Nullen dürfen mit negativen Indizes gemischt werden # 2.3 Vektoren mit character --------------------------------------------------- # Zahlen als Text (R kann damit nicht rechnen, ist als Überschrift sinnvoll) ( vekt6 <- as.character(1:3) ) # Zusammengesetzte Vektoren ( vekt7 <- c(vekt1, -7:10, vekt2) ) # Namen zuordnen ( vekt8 <- c(2:4) ) vekt9 <- c("a","b","c") vekt9 names(vekt8) <- vekt9 vekt8 # ist nach wie vor ein Vektor, und keine Tabelle! vekt8["b"] seq(7, 8, .3) rep(1:4, 2) rep(1:4, each=2) paste("WunderbareSache", 3:5) # macht einen Vektor mit Modus character paste(2, "hot", 4, "U") paste("SeeYouL", vekt7[5], "ter", sep="") # Auf bestehende Objekte zugreifen # sep steht für Separation, dem Trennzeichen zwischen den Zeichenketten. # 2.4 Basic Statistics --------------------------------------------------------- Noten <- c(3.0, 2.3, 5, 1.3, 4, 1.7) Noten # Objekt anzeigen lassen mode(Noten) # numeric also Zahlen mean(Noten) # Mittelwert var(Noten) # Varianz sd(Noten) # Standardabweichung median(Noten)# Median: Zahl an mittlerer Stelle der nach Größe sortierten Werten # 2.5 oft verwendete Operatoren ------------------------------------------------ length(vekt1)# Anzahl Komponenten (Elemente) eines Vektors length(vekt6) max(vekt1) # Wert des größten Elements in vekt1 max(vekt2) max(vekt2, na.rm=T) # NA Werte nicht berücksichtigen (steht für NA.ReMove) vekt2 <- replace(vekt2, 8:9, 5) # ersetzt die Elemente 8:9 zum Wert 5 vekt2 max(vekt1, vekt2) range(x) # entspricht c(min(x), max(x)) which.max(x) # Index des größten Elements in x which.min(x) # Index des kleinsten Elements in x sum(vekt1) # Summe der einzelnen Elemente vekt2 sum(vekt2) cumsum(vekt2) # kumulierte Summe bis zum jeweiligen Element sum(vekt1, vekt2) # sum nimmt mehrere Daten, ohne dass diese erst # zu einem Vektor zusammengefügt werden müssen. Bei mean ist das zB anders: mean(vekt1, vekt2) # geht nicht mean( c(vekt1, vekt2) ) # prod() # Produkt # union() # Teilmenge # intersect() # Schnittmenge # rev() # reverse, kehrt Reihenfolge um # sort() # sortiert Vektoren # Ist ein bestimmter Wert (5) in einem Datensatz (y) enthalten? y <- 3:17 is.element(5, y) # identisch zu x %in% y 2 %in% y # ><= Abfragen ( k <- c(1,5,3,2,7,6,1,2,8) ) which(k==2) # Welche Elemente sind = 2 ? k[k==2] <- 2.5 # ändere alle 2 zu 2.5 k subset(k, k>3) # Welche Werte haben die Elemente mit Wert > 3 ? # 2.6 Tabellen ----------------------------------------------------------------- # Dataframes = Tabellen mit verschiedenen Datentypen # data.frame( Spaltenname = Vektor, zweiteSpalteÜberschrift = andererVektor) tab1 <- data.frame(N=11:17, K=letters[1:7], Logisch=(1:7)>2) tab1 # data.frame ist das gängigste Tabellenformat. # Anzahl Reihen(Zeilen) / Spalten im Datensatz nrow(tab1) ncol(tab1) dim(tab1) # häufige Fehlermeldung: "Fehler in ____nrow(xx)____ : Argument hat Länge 0 " # evtl ist xx ein Vektor --> nehme length(xx) statt nrow(xx) / dim(xx) # Namen der einzelnen Datenspalten aufrufen names(tab1) str(tab1) # STRucture: Zeigt Objekttyp sowie Datentyp einzelner Spalten an class(tab1) # data.frame mode(tab1) # Obertyp list, hier erstmal irrelevant # 2.7 Tabellenindizierung ------------------------------------------------------ # Auf Elemente der Tabelle zugreifen: Objekt[Zeile,Spalte] tab1[2,3] # Ausgabe des zweiten Elementes der dritten Spalte # Beim weglassen der Angabe von Zeile oder Spalte werden alle genommen: tab1[ ,2:3] # Ausgabe einzelner Spalten als Spalte (Dataframe) tab1[3,] # Ausgabe einer Zeile tab1["K"] # Ausgabe einer Spalte als Dataframe tab1 [3] # andere Methode für's gleiche tab1[,3] # Ausgabe der Spalte als Vektor tab1$K # dito tab1[1:4,3] # Ausgabe eines Teils der Spalte als Vektor tab1[1:4,3, drop=F] # Bleibt ein data.frame # Noch mehr Beispiele in Kapitel 3.3 as.character(tab1) # geht manchmal nicht für Tabellen oder macht Vektor draus # Zeilen entfernen d <- data.frame( a=1:10 , b=11:20 ) d ( e <- d[-(3:5),] ) # Wertebedingt indizieren blub <- data.frame(w=c("a001","b476","b342","a677"), A=c(4,5,3,2), B=c(2,4,3,6), C=c(2,8,4,1) ) blub blub[,2] <5 blub[blub$A<5,] blub[blub$A<5 & blub$B<5,] blub[blub[,2]<5 & blub[,3]<5,] # 2.8 Tabellen zusammenführen -------------------------------------------------- # Mit rbind(a,b,d) lassen sich die Vektoren a, b und d reihenweise zu einer # Matrix zusammenführen. # Im Gegensatz dazu verbindet cbind() die Vektoren spaltenweise zu einer Matrix. # data.frame() macht das auch so wie cbind. f <- data.frame(a=11:14, b=58:55, d=236:233) g <- data.frame(a=33:36, b=76:79, d=-28:-31) f g rbind(f,g) # Spaltenanzahl ncol der beiden Matrizen muss gleich sein cbind(f,g) # Zeilenanzahl nrow der beiden Matrizen muss gleich sein # 2.9 Zeilen- und Spaltennamen zuordnen ---------------------------------------- a <- data.frame( 5:-1, c(3,5,1,9,6,4,8) ) ; a colnames(a) <- c("alles","klar") ; a rownames(a) <- LETTERS[a$klar] ; a # 2.10 Matrizen ---------------------------------------------------------------- # matrix ist ein weiterer Objekttyp. Hat anders als Dataframe nur 1 Datentyp! # Matrix erstellen und füllen (m <- matrix(NA, nrow=5, ncol=3)) m[4,2] <- 17 ; m m[1,] <- 8 ; m m[,3] <- 3:7 ; m ( m[5,] <- LETTERS[4:6] ) m # matrix kann nur 1 Modus haben, darum wird jetzt alles in char umgewandelt! noquote(m) # Gibt die Character ohne Anführungsstriche aus str(m); class(m); typeof(m) # bleibt eine matrix mit charactern # Lineare Gleichungssysteme lösen x1 x2 b A <- matrix(c(16,4,74,16), ncol=2, byrow=T) ; A # 16 4 | 25 b <- c(25,113) # 74 16 | 113 solve(A, b) # 1.30 1.05 1.3 * 16 + 1.05 * 4 # 25 1.3 * 74 + 1.05 * 16 # 113 Die Resultate sind richtig... -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 3: Dateien und Arbeitsverzeichnis ################################## # 3.1 Arbeitsverzeichnis # 3.2 Tabellen einlesen # 3.3 Anzeigen ausgewählter Elemente # 3.4 attach # 3.5 Tabelle exportieren (schreiben) # 3.6 Oft verwendeter Operatoren # 3.7 Excel-Dateien lesen und schreiben # 3.1 Arbeitsverzeichnis (Working Directory) ----------------------------------- # An diesem Ort (Ordner) werden Dateien gelesen und gespeichert, sofern nicht # der ganze Pfad angegeben wird. Dadurch kann ein Ordner mit Dateien und Skript # einem Kollegen gegeben werden, ohne das der alle Pfade ändern muss. # Schnelles und reproduzierbares Einstellen mit dem Befehl setwd: setwd("D:/Ordner/BerryIstToll/Rclick_Handbuch") # alle \ umwandeln in / oder \\. Bei langen Pfaden im TinnR STRG + R nutzen! # ( \ ist in R die EscapeSequenz aus einer Zeichenkette heraus) # Tipp: Im Windows Explorer Datei markieren, F4 drücken um den Pfad zu kopieren. # Tipp: Wähle sinnvollerweise gut zugängliche Ordner aus. # Alternativ per Maus, aber anderen Skriptlesern dann nicht ersichtlich: # In der R Console "Datei" klicken, dann "Verzeichnis wechseln". # Überprüfen des aktuellen Verzeichnisses mit getwd() # Wenn ein R-Skript in Tinn-R geöffnet wird, und danach R selbst mit Tinn-R # geöffnet wird, ist das Arbeitsverzeichnis automatisch der Ordner, in dem die # R-Datei sich befindet. Wenn also die Daten im gleichen Ordner wie das R-Skript # vorliegen, entfällt die meiste Arbeit mit dem Working Directory. # Anzeigen der Datei(en) im Arbeitsverzeichnis dir() # Übersicht der Dateien und Ordner (keine Unterordner) dir("S:/Dropbox/Public/Rclick", recursive=T) # mit Dateien in Unterordnern file.info(dir()) # Detaillierte Übersicht file.show("Daten/3_Einlesen.txt" ) # eine Datei anzeigen # Dateinamen sind, anders als Zuordnungen, nicht case-sensitive (GROSS/klein). getwd() setwd("..") # 1 Ordner aufwärts. mit setwd("/") zur Partition, z.B. "D:/" getwd() # 3.2 Tabellen einlesen -------------------------------------------------------- MeiTab <- read.table("Daten/3_Einlesen.txt", header = T) # Der Dateiname kann auch als ganzer Pfad angegeben werden, bei Weitergabe von # Skripten und Daten sind aber relative Pfade ganz toll! # read.table wichtigsten Argumente # header = TRUE übernimmt Spalten-Überschriften # dec = "," liest Kommas als Dezimaltrennstellen # sep = "-" Nimmt Striche als Spaltentrennung an # fill = T füllt Lücken in den Daten mit NA # (bei fill=F (Default!) müssen alle Zeilen und Spalten gleich lang sein) # skip = 12 überspringt die ersten 12 Zeilen (zB mit Metadaten) # comment.char = "%" überspringt Zeilen, die mit % anfangen (wie # in R) # read.csv() für csv-tabellen und read.csv2() für deutsche Tabellen. # Excel-Tabellen möglichst als txt-Dateien exportieren ("Speichern unter") ?stackloss # Wärme-Abgasverlust - Effizienz industrieller Ammoniumoxidation # Spaltennamen anzeigen names(MeiTab) # Grundlegende statistische Auswertung (Zusammenfassung) der Daten summary(MeiTab) # häufige Fehlermeldung beim Laden von Tabellen # "Kann Datei ___ nicht öffnen: No such file or directory" # --> Verzeichnis oder Pfad kontrollieren: getwd() # --> Dateiname kontrollieren # --> Wird die Datei mit Anführungsstrichen aufgerufen? # Wer viele Excel-Dateien einlesen muss: Ganz unten Abschnitt 3.7 lesen # 3.3 Anzeigen ausgewählter Elemente ------------------------------------------- # (können durch Zuordnung auch als neue Tabelle/Vektor gespeichert werden) MeiTab["Air.Flow"] # Spalte "Air.Flow" als Spalte eines Dataframes MeiTab[1] # Spalte 1 als Spalte MeiTab$Air.Flow # Spalte "Air.Flow" als Vektor MeiTab[,"Air.Flow"] # Spalte "Air.Flow" als Vektor MeiTab[,1] # Spalte 1 als Vektor MeiTab[1:3] # Spalten 1 bis 3 MeiTab[3:7,2:3] # Teil der Tabelle MeiTab[1,] # Zeile 1 als Tabelle MeiTab[1:3,] # Zeilen 1 bis 3 MeiTab[ 6:12 , 2:3 ] # Zeilen 6 bis 12, Spalten 2 und 3 MeiTab[1,"Air.Flow"] # Element der Zeile 1 in der Spalte "Air.Flow" MeiTab[ 1:3 , 4 ] # Zeilen 1 bis 3 in Spalte 4 als Vektor MeiTab[MeiTab$Air.Flow<60,] # Tabellenzeilen mit Air.Flow < 50 MeiTab[MeiTab$Air.Flow>=70,] # Tabellenzeilen mit Air.Flow grösser/gleich 70 MeiTab[MeiTab$Air.Flow==62,] # Tabellenzeilen mit Air.Flow = 62 MeiTab[MeiTab$Air.Flow!=62,] # Tabellenzeilen mit Air.Flow ungleich 62 MeiTab$Water.Temp[MeiTab$Air.Flow>70] # Water.Temp mit Air.Flow > 70 # Ausgaben als Spalte (Data.Frame) sind übersichtlich # Mit Vektoren kann aber oft bessser gerechnet werden mode(MeiTab[1]) ; mode(MeiTab[,1]) # häufige Fehlermeldung: Fehler in "__": undefined colums selected. # --> beachte das Komma! Objekt[zeilen , spalten] # --> dim(Objekt) zeigt dir, ob es überhaupt soviele Spalten hat, # wie du ansprechen willst. # 3.4 schlechtes Programmieren: attach ----------------------------------------- # Anhängen einer Tabelle # mit attach() wird ein data.frame in den R Suchpfad eingebunden # die einzelnen Spalten können jetzt mit ihrem Namen direkt angesprochen werden. # Sind aber keine Objekte im normalen Environment (Vgl ls() vor und nach attach) ls() Air.Flow # noch nicht bekannt attach(MeiTab) Air.Flow # jetzt direkt abrufbar ls() log(Air.Flow) # als Zeile (Vektor, "numeric") log(MeiTab["Air.Flow"]) # als Spalte (Tabelle, "list") MeiTab[Water.Temp>22,] # attach ist generell eine Unsitte, weil man später nicht weiß, woher ein objekt # kommt: aus dem normalen Workspace oder aus einer Dataframe. # Und es kann Objekte und Funktionen im Base "überschreiben". search() # zeigt Suchpfad, wo die angehängten Sachen sind # Abhängen einer Tabelle (Die Tabelle selbst ist weiterhin im Workspace) detach(MeiTab) # 3.5 Tabelle exportieren (schreiben) ------------------------------------------ # Wenn kein Pfad angegeben, wird im working directory abgespeichert write.table(tab1, "MeineErsteTabelle.txt", row.names=F, sep="\t", quote=F) # row.names = FALSE : Abspeichern ohne Zeilennummern links # col.names = FALSE : Spaltenüberschriften nicht mitschreiben # quote = FALSE : Keine Anführungsstriche in die Textdatei schreiben # sep = "\t" : Daten tabstopp-getrennt speichern (ab 7 Zeichen pro Spalte # ist die Darstellung im Editor verschoben). Zum Copypasten in Excel hinein. # Escape-Sequenz "\" im Character belegt, Siehe Kap 17.1 # Kann daher für Verzeichnisse nicht genutzt werden (siehe oben unter 3.1). # 3.6 Oft verwendeter Operatoren (to be continued) ----------------------------- MeiTab order(MeiTab$Water.Temp) # Reihenfolge MeiTab[ order(MeiTab$Water.Temp) , ] # Tabelle sortiert nach Wassertemperatur nrow(MeiTab) # Anzahl Zeilen (rows) ncol(MeiTab) # Anzahl Spalten (columns) dim(MeiTab) # entspricht c(nrow(),ncol()), macht das aber auch für arrays t(MeiTab) # transponieren: Zeilen zu Spalten, Spalten zu Zeilen ?split() # Vektoren zerlegen data() # bestehende (R- oder Package-integrierte) Datensätze anzeigen # Und für Matrizenoperationen: ?det() # Determinante einer Matrix ?solve(A,b) # Lösung des Gleichungssystems A x = b ?crossprod(X,Y) # Kreuzprodukt zweier Matrizen ?qr() # QR-Matrixzerlegung ?eigen() # Eigenwerte und -Vektoren ?"%*%" # Produkt zweier Matrizen / Skalarprodukt zweier Vektoren # 3.7 Excel-Dateien lesen und schreiben ---------------------------------------- # http://cran.r-project.org/doc/manuals/R-data.html#Reading-Excel-spreadsheets # Für Excel 2007/2010/2013 siehe besonders das Paket xlsx # Einzelne Dateien lassen sich schneller als Text- oder CSV-dateien speichern. # Zunächst Java installieren, falls nicht vorhanden: browseURL("http://www.java.com/en/download/manual.jsp") # ASK Toolbar beim Installieren ausschalten # Beim Fehler JAVA_HOME cannot be determined from the Registry: Sys.setenv(JAVA_HOME='C:\\Program Files\\Java\\jre7') # for 64-bit version Sys.setenv(JAVA_HOME='C:\\Program Files (x86)\\Java\\jre7') # for 32-bit version library(rJava) if(!require(xlsx)) install.packages("xlsx") library(xlsx) read.xlsx("filename.xlsx", sheetIndex=2) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 4: Graphische Datenauswertung ###################################### # 4.1 Basics: Beschriftungen, Symbole # 4.2 Linien statt Punkte, Überplotten # 4.3 Graphikausschnitte, Ränder, Barplots # 4.4 par # 4.5 Farben, Legende # 4.6 Linien, Text, Gitter # 4.7 Achsenbeschriftungen 2.0 # 4.8 Logarithmierte Achsen mit Linien im Plot # 4.9 Anordnung mehrerer Graphiken in einem Bild # 4.10 Graphiken mit Umrandung # 4.11 Speichern von Bildern: bmp("dateiname.bmp") # 4.12 Beidseitige y-Achsenbeschriftung # 4.13 Achsen unterbrechen, Pakete installieren und laden # 4.14 mehrdimensionale Info in Graphiken # 4.15 Dreidimensionales Plotten # 4.16 Fehlerbalken (Error bars) # 4.17 Fläche unter Graphen füllen # 4.18 Funktionen zeichnen # 4.19 zooming in graphics # 4.20 und ein würdiger Abschluss des Kapitels # 4.21 Übersicht der wichtigsten Graphikbefehle # integrierter Datensatz (Beispieldaten aus Kapitel 3) Daten <- stackloss ; names(Daten) <- c("Air", "Water", "Acid", "StackLoss") Daten # Zuordnungen können unter x-beliebigem Namen laufen, eben zB "Daten". ?stackloss # aber nicht "data" weil das schon eine Funktion ist # Grundlegende Graphiken (x-y-Plot) ?plot plot(Daten$Air, Daten$StackLoss) # manchmal ist auch pairs interessant: pairs(Daten) # Intro in R's Graphikkapazitäten (Befehle sind jetzt egal, später anschauen) demo(graphics) # in der Console ENTER drücken, dann auf die Bilder klicken # Evtl. kommt zuerst ein leeres Grafikfenster, dann einmal darin klicken. dev.off() # Schließt Graphikfenster #http://blog.revolutionanalytics.com/2015/01/some-basics-for-base-graphics.html # 4.1 Basics: Beschriftungen, Symbole ------------------------------------------ # Beschriftungen: main = "Überschrift", sub = "Unterschrift", xlab = "X-Achse" plot(Daten$Water, Daten$StackLoss, main = "StackLoss abh. der Wassertemperatur", sub = "Analyse", xlab = "Wassertemperatur", ylab = "StackLoss") # Immer wenn ein + in R erscheint, ist die Eingabe noch nicht abgeschlossen. # später hinzufügen mit title() plot( c(8,4,14,-3,4,15) , xlab = "") # Wenn nur ein Vektor angegeben wird, wird über ganze Zahlen geplottet (Index) title(main = "Hallo", xlab = "Dies ist die X-Achse") # Zeilenumbruch im Titel: \n ohne Leerzeichen im Text einfügen plot(Daten$Water, Daten$StackLoss, main = "tolle Graphik\nStackLoss") # Punkt- und Schriftgröße verändern: cex = ___ ( Character EXpansion) plot(Daten$Water, Daten$StackLoss, cex = 2) plot(Daten$Water, Daten$StackLoss, cex = 2, main = "Schuhgröße - StackLoss", cex.main = 2) # Default: cex.main=1.2 # Achsenwerte ("label" = Zahlen / Einheiten an Achsen) skalieren: cex.axis = ___ plot(Daten$Water, Daten$StackLoss, cex.axis = 0.5) # Ausrichtung der Achsenwerte: las = ___ 0 parallel zur Achse, 1 horizontal plot(Daten$StackLoss, las = 1) # 2 quer zur Achse, 3 vertikal # (Label Axis Style) # Symbole ändern: pch = ___ oder pch="Buchstabe" zB. ausgefüllter Punkt: pch=16 plot(Daten$Water, pch = 16) # (Point Character) Siehe Übersicht im Anhang # Achsentitel ausrichten (adjust); Werte von 0 (Text links) bis 1(Text rechts) plot(Daten$Acid, adj = 0.82) # Kombination von Parameter-settings (Reihenfolge ist egal) plot(Daten$Air, main = "N in Pflanzen", xlab = "WasserTemp", ylab = "Stack Loss", las=3, pch = 16, cex = 1.5) # Abstand Beschriftung: mgp=c( Achsentitel, Achsenwerte, Achsen) # Voreinstellung: mgp=c(3,1,0), somit Verschiebung nach innen und außen möglich plot(Daten$Water, mgp=c(3.5, 1, 0)) plot(Daten$Water, mgp=c(2, 1, 0)) # könnte für MarGinPlacement stehen... plot(Daten$Water, mgp=c(3, -1, 0)) plot(Daten$Water, mgp=c(3, -3,-2)) # 4.2 Linien statt Punkte, Überplotten ----------------------------------------- k <- c(3,0,-10,8,6,3) ; l <- c(-4,2,-6,-12,7,-3) plot(k) # standard (default) type: "p" (points) plot(k, type="l") # Linien plot(k, type="b", lwd=4) # Liniendicke einstellen plot(k, type="o", lty=2) # Linientyp einstellen # Siehe Übersichten im Anhang zu type und lty # mit dem Befehl points() kann etwas in die Graphik eingefügt werden. # Die Argumente sind gleich wie bei plot(), allerdings ohne Titel. plot(k) points(l, pch=24, bg=2) lines(l) # wie points mit als Standard type="l" plot(k, type="o") # "b": Punkte und Linien. "o" zieht die Linien durch par(new=T) # Ein danach versandter plot wird über das alte geplottet. plot(l, type="o", col=6, col.axis=6) # Achsen vermurkst! # (Zweiseitige Achsen werden im Kapitelteil 4.12 vorgestellt.) plot(k, type="b", lty=2) # Plot von gerade wieder (new=T gilt nur für 1 Graphik) par(new=T) plot(l, type="o", ylim=c(-10,8), pch="@") # Die y-Achsengrenze des ersten Datensatzes reicht nicht, daher ylim: Kap 4.3. # 4.3 Graphikausschnitte, Ränder, Barplots ------------------------------------- # Plotausschnitt einstellen: xlim = c( untere Grenze, obere Grenze ) plot(Daten$StackLoss,xlim=c(-3,50), ylim=c(-4,80)) # Graphik ohne 4%-Erweiterung des Achsenbereiches: yaxs="i" (Y-AXis Style) plot(c(3,2,5,4), type="o") plot(c(3,2,5,4), type="o", yaxs="i", xaxs="i") # Ränder (Margins) einstellen: mar = c(bottom, left, top, right) # Die Nutzung von par ist im nächsten Abschnitt erklärt. par(mar = c(5, 4, 4, 2)+0.1 ) # Default Settings (Voreinstellung) plot(Daten$Water) # mar muss immer mit par für das Device gesetzt werden par(mar=c(2.2, 2.0, 0.2, 2.1) ) plot(Daten$Water) # Barplots: tabelle <- read.table(header=TRUE, text=" LandN. Verdunstung Wald 200 Weide 400 Soja 359") tabelle barplot(tabelle$Verd, names=tabelle$LandN, main="Verdunstung", col=c("forestgreen","green2","wheat")) # 4.4 par ---------------------------------------------------------------------- # viele der Graphik-Einstellungen können auch mit par eingestellt werden. # Die danach im gleichen Fenster erstellten Plots haben dann die Eigenschaften. # Weitere Fenster können mit windows() eröffnet werden. windows() # geht nur mit dem Betriebssystem Windows, sorry Linuxer. # (Macser: selbst Schuld 😉 Kauft was billigeres oder kostenloses...) # verschiebe mal das neue Fenster (Device 3) plot(Daten$Air, Daten$Water) dev.off() # schließt das aktuelle (active) Fenster graphics.off() # macht alle zu # Aktuelle Settings anzeigen (Default, da alle Graphikfenster jetzt zu sind) par() ?par # Alte Graphikeinstellungen (Parameter) im Graphics:Device speichern altepar <- par(mar=rep(6,4)) # speichert das alte (!) mar altepar # in Funktionen oft old.par oder op genannt plot(1:8) par(altepar) # vorherigen Rand wieder einstellen par(new=T, col="red", col.axis="red", col.lab="red") # Farben Siehe 4.5 plot(1:8) # Alternativ möglich: old.par <- par(no.readonly=T) # Nur nötig, wenn Änderungen im Device mit par(___) vorgenommen werden # Nicht nötig, wenn Einstellungen in einzelnen Graphiken erfolgen. plot(x,y,___) dev.off() # Randplatz minimieren, Graphikraum maximal nutzen: par(mar=c(3,3,1,1), mgp=c(1.8, 0.6, 0), las=1) plot(Daten$Air, Daten$Water) # Einstellungen mit par gelten für Graphen, die im aktuellen, aktiven, Fenster # erstellt werden. Wird dieses geschlossen, müssen sie erneut gesetzt werden. # Graphik History (zeichnet einzelne Ausgaben im Graphics:Device auf) # Bild wechseln mit "Bild up" und "Bild dn" Tasten oder Mausklick windows(record=T) # oder im Device selbst unter History anklicken # praktisch: Rechtsklick in der Graphik - "bleibe im Vordergrund" anschalten graphics.off() # 4.5 Farben, Legende ---------------------------------------------------------- # Farben setzen: col = ___ plot(Daten$Water, Daten$StackLoss, col = "red") # oder col=2 plot(Daten$Water, Daten$StackLoss, col = rgb(0,1,0), pch=16) # RGB steht für RedGreenBlue. Ermöglicht exakte Farben zB nach Corporate Design rgb(0,1,0) # Hat Standardwerte zwischen 0 und 1 col2rgb("green")/255 # Hat Standardwerte zwischen 0 und 255 plot(1:3, pch=16, cex=3, col= rgb(c(0,.3,.8), c(.3,.5,.5), c(.1,.9,.2) ), las=1) # Siehe auch ?hcv und ?hsl plot(Daten$StackLoss,Daten$Air, col.axis=6, font=2) # font=2 ist fette Schrift (bold). font.lab ist für die Achsentitel colors() # Siehe Anhang und http://fany.checkts.net/Farben.html # Die acht Schnellfarben, die standardmäßig in palette() sind: plot(1:8, col=1:8, pch=16, cex=4, xlab="plot ( 1:8, col=1:8 )") # Hintergrundfarbe einstellen par(bg=3) # BackGround plot(1,1, pch=16) dev.off() # Achsenfarben setzen: par(col=__) old.par <- par(col=2, cex.axis=2, bg=8) plot(1,1) plot(Daten$Water, Daten$Acid) # alte Grafikeistellungen wiederherstellen par(old.par) plot(Daten$Water, Daten$Acid) # Alternativ das Graphikfenster schließen (geht auch normal übers "Kreuzigen"): dev.off() # Beim nächsten Plotten sind die Settings wieder im Ursprungsformat # Farben der Achsenwerte (Einheiten) : col.axis # und der Beschriftungen (Labels): col.lab plot(1, col.axis = "sky blue", col.lab = "brown") # Symbole mit Farben füllen plot(1,1, pch= 1, cex=4) # (Point CHaracter, Character EXpansion) plot(1,1, pch=21, cex=4) # pch 21 bis 25 können eingefärbt werden. plot(1,1, pch=21, cex=4, bg=3) # --> Übersicht der Symbole im Anhang # bg hat hier also eine andere Bedeutung, als wenn es in par() gesetzt wird. # bedingt einfärben: col = ifelse(wenn, dann, sonst) plot(Daten$Water, Daten$StackLoss, col = ifelse(Daten$StackLoss > 18, "blue", "red"), pch=15) plot(Daten$Water, Daten$StackLoss, col = ifelse(Daten$Acid > 87, "blue", "red"), pch=15) # Legende hinzufügen: legend(x,y-position der linksoberen Ecke, Einträge, ___) legend(18, 35, c("Acid > 87", "Acid <= 87"), col=c(4,2), pch=15) plot( c(1,3,2,5), type="l") # Eine Übersicht der TYPEs ist im Anhang. legend("topleft", c("Hallo", "R-Lerner"), lty=1) # Line TYpe siehe Anhang legend(3, 4, c("CheckThisOut",1,2), pch=1:3, bg="white") legend(1.5, 3, c("Party","People"), title="Legende", bty="n", fill=3:4) legend("bottom", c("Und", "tschüss"), inset=0.01, lty=c(NA, 2), pch=c(3,NA)) # Farbenrad aus der demo(graphics) pie(rep(1,24), col=rainbow(24), radius=0.9) k <- c(3,1,10,8,6,3) pie(k) # PieCharts sind fast nie geeignet, Daten adäquat zu visualisieren: browseURL("www.storytellingwithdata.com/2011/07/death-to-pie-charts.html") browseURL("http://www.perceptualedge.com/articles/08-21-07.pdf") browseURL("http://www.stevefenton.co.uk/Content/Pie-Charts-Are-Bad/") browseURL("http://blog.jgc.org/2009/08/please-dont-use-pie-charts.html") browseURL("http://www.juiceanalytics.com/writing/the-problem-with-pie-charts/") browseURL("http://eagereyes.org/techniques/pie-charts") # 4.6 Linien, Text, Gitter ----------------------------------------------------- # Linie(n) einzeichnen: abline(a=Y-Schnittpunkt, b=Steigung, h=Y-wert, v=X-wert) plot(Daten$Water, Daten$StackLoss) abline(h=20) # horizontale, waagerechte Linie abline(v=24) # vertikale, senkrechte, Linie abline(a=-38, b=3) # schräge Gerade: a = Y-Schnittpunkt, b = Steigung (!) abline(5, 0.7, col=6, lty=2, lwd=2) # Gerade ist also y = a + bx # Graphikfenster öffnen, ohne zu zeichnen: type="n" für none/nothing/nichts/nada # Verhältnis X zu Y (ASPect ratio): asp = ___ (je gleich groß: asp=1) plot(c(-2,3), c(-1,5), type="n", xlab="x", ylab="y", asp=1) abline(h=0, v=0, col="gray60") # Text hinzufügen: text(x,y-Koordinaten, "text", Ausrichtung vom Punkt aus text(1, 0, "abline( h = 0 )", col = "gray60", adj = c(0, -.1)) # adj: s. Anhang text(1, 2, "fette Schrift", col = "gray60", font=2) # font: Übersicht im Anhang # Schriftart verwenden: windowsFonts(MyFont = windowsFont("Georgia")) windowsFonts() # Für alle Bilder: am Skriptanfang par(family="MyFont") plot(1:100, type="l") # einzeln: mit family in plot, text, mtext, etc plot(1:100, type="l", family="sans") # Arial, bei mir Default plot(1:100, type="l", family="MyFont") # Georgia plot(1:100, type="l", family="mono") # Courier New plot(1:100, type="l", family="serif") # Times New Roman windowsFonts(Bookman = windowsFont("Bookman Old Style"), Comic = windowsFont("Comic Sans MS"), Symbol = windowsFont("Symbol")) plot(1:100, type="l", family="Bookman") plot(1:100, type="l", family="Comic") plot(1:100, type="l", family="Symbol") # Linientyp einstellen: lty = ___ abline(h = -1:5, v = -2:3, col = "lightgray", lty=3) abline(a=1, b=2, col = 2) text(1, 3, "abline( 1, 2 )", col=2, adj=c(-.1,-.1)) plot(8:5, pch=22, cex=3, bg=5) grid(col=2) # überzeichnet die Ergebnisse, diese können neu gelegt werden points(8:5, pch=22, cex=3, bg=5) # LinienEnd-typen einstellen (geht heutzutage auch im Plot-Befehl) plot(c(5,5), lwd=8, type="l") par(lend="butt") # 0="round" (Default), 1="butt", 2="square" points(c(4,4), lwd=8, type="l") # 4.7 Achsenbeschriftungen 2.0 ------------------------------------------------- # Achsenbeschriftungen hinzufügen: axis(welche, wo, was) # welche: 1=unten, 2=links, 3=oben, 4=rechts plot(67:88, yaxt="n", xaxt="n") axis(2, 69 ) # einzelne Werte axis(2, 76, "Grenze", las=1) # mit Text (oder anderen Zahlen) axis(2, 83, "Gr2", las=1, col.axis=2, col=8) # schön farbig axis(2, 86, tick=F, las=1) # ohne Striche axis(3, 5, labels=F) # ohne Werte axis(1, 5:7, col=5, col.axis=2) # Intervallachse bei mehreren Positionen axis(1, pretty(10:30) ) # pretty wählt schöne Zahlen bm <- prettyNum(c(10000, 20000, 30000), big.mark="'"); bm # Tausend-Trennpunkte axis(4, c(70,75,80), bm) axis(3, 13:16, col="orange", lwd=0, lwd.ticks=3) # no line axis(3, pos=par("usr")[3], col.axis=4, font.axis=2) # Striche nach Innen axis(2, 78, tcl=0.5, mgp=c(0,-1.8,0), las=1) # Striche nach Innen (besser) # die letzte Zahl von mgp ist hier für die Ticks (= Striche) und nicht # für die Achsen selbst, wie im Abschnitt Basics axis(1,15.5, "", tcl=-0.4, col.ticks="purple") plot(5:9, xlab=expression(Das~underline(sind)~italic(meine)~bold(Daten)~hier) ) ?expression ?plotmath ?axTicks() plot(c(5,-2,7,8), main=c("per Hand geteilte",""), col.main=2) title(main=c("","Überschrift"), col.main=4, cex.main=.7) # 4.8 Logarithmierte Achsen mit Linien im Plot --------------------------------- # Beschriftungen: 10^(-3:4) options("scipen"=4) # scientific penalty, siehe ?options 10^(-3:4) options("scipen"=4) format(10^(-3:4), big.mark="'", trim=TRUE ) options("scipen"=0) format(10^(-3:4), big.mark="'" ) install.packages("berryFunctions") require(berryFunctions) plot(1, ylim=c(1e-3, 1e4), log="y", yaxt="n", yaxs="i") logAxis(2) lines(seq(0.5, 1.5, len=50), 10^runif(50, -3, 4), col=2) str(logVals()) # vals: values, labs: formatted labels, all: all 10^x values for lines # 4.9 Anordnung mehrerer Graphiken in einem Bild ------------------------------- # mehrere Graphiken pro Fenster (Layout-Aufteilung) par(mfrow=c(3,2)) # 3 Zeilen, 2 Spalten - 6 Graphiken in einem Fenster plot(stackloss[,1:2]) plot(stackloss[,2:3]) # 6 (verschiedene) plot-Befehle an R schicken # Zurücksetzen auf eine Grafik pro Fenster par(mfrow=c(1,1)) # oder schließen und mit plot(x, y, ___) neu öffnen # flexiblere Anordnung mehrerer Graphiken im Graphics:Device layout(matrix(1:6, 3, 2), widths=c(7, 5), heights=c(1,1,1)) plot(stackloss[,1:2]) # widths und heights werden jeweils anteilig gesetzt plot(stackloss[,2:3]) ?layout # mehrere Graphiken auf einem Blatt: absolute Größen (in cm) # zB. für quadratische plots. Grafikfenster vorher ausreichend groß ziehen! layout(matrix(1:3, 1 ,3), widths=lcm(c(5, 5, 5)), heights= lcm(5)) # Layout anzeigen m <- layout(matrix(1:6, 3, 2), widths=c(8,3), heights=c(2,4,1)) layout.show(m) lay <- layout(matrix(c(1,1,2,2, 5,5,2,2, 3,3,4,4, 3,3,4,4), ncol=4, byrow=TRUE)) layout.show(lay) lay <- layout(matrix(c(2,2, 2,2, 1,5, 3,5, 4,4, 4,6), ncol=2, byrow=TRUE) ) layout.show(lay) dev.off() # margin-text (Text in den Rändern) layout(matrix(1:2, ncol=2), width=c(2.7,1)) plot(1) mtext("rechts", side=4, col=4) mtext("plot region", adj=1) mtext("outer margin", adj=1, outer=TRUE, line=-1) box("figure", col=2) mtext("Figure", at=par("fig")[2], adj=1, outer=TRUE, line=-2) # Graphiken übereinander zeichnen: browseURL("http://www.statmethods.net/advgraphs/layout.html") graphics.off() # etwaige alte Einstellungen löschen - neu beginnen plot(rnorm(10)) par(fig=c(0,0.6, 0.6, 0.95), mar=rep(0,4), new=T) plot(1, ann=F, axes=F) pu <- par("usr") ; rect(pu[1],pu[3],pu[2],pu[4], col=3); rm(pu) par(mar=c(3,4,1,1), new=T) plot(rnorm(80)) # Aspect Ratio (potentiell wichtig) x <- (1:50)*0.92 ; y <- sin((1:50)*0.92) # http://www.amazon.com/dp/0521762936 plot(x,y) plot(x,y, asp=3) # 4.10 Graphiken mit Umrandung ------------------------------------------------- par(oma=c(1,2,2,4)) # outer margins lay <- layout(matrix(c(1,1,2,3, 4,4,4,4, 5,5,5, 6), ncol=4, byrow=TRUE) ) layout.show(lay) # Wenn man mit Layout arbeitet, sollte man vorm ersten Plot par(cex=1) setzen! plot(1:9) par(cex=1) plot(2:-5) box(lwd=2, col=7) box("figure", col=2) box("inner", col=3) box("outer", col=4, lwd=4) graphics.off() hist(rnorm(20)) # 20 Zufallszahlen aus der Normalverteilung. Mehr in Kap. 5 # Histogramm siehe Kapitel 6. box(col = "blueviolet", lwd=3, lty=2) # zB wichtig nach abline, da das den Rand der Graphik selbst überplottet. win.graph(width=3, height=2) # Öffnet Graphikfenster bestimmter Größe (inches) # 4.11 Speichern von Bildern: bmp("dateiname.bmp") ----------------------------- # automatisch im WorkingDirectory, ansonsten im Dateinamen den Pfad einfügen png("MeinBild.png") # Defaultbildgröße: 480 x 480 Pixel # danach die Graphikbefehle abschicken plot(1:10) dev.off() # Device auch wieder schließen! getwd() # Schau dir das Bild hier im Explorer deines Computers an... # praktisch unter Windows: # Im Graphikfenster - Datei - Speichern als - png plot(c(7,5,11,2,4), type="b") # aber nicht reproduzierbar! # *.wmf file that can be copy-pasted into a word file: win.metafile("mygraph.wmf") # funktioniert nicht immer gut! plot(cumsum(rnorm(30)), type="l") # Und nur unter Windoof. dev.off() # Zum Publizieren geeignete Bildformate: png("MeinBild.png", width=600, height=400, units="px") # png ist ein gutes, kleines, genaues Format # 600 x 400 ist ganz gut, um direkt in DIN A4 (Word-)Dokumente einzufügen. plot(1:10) dev.off() png("MeinBild.png", width=4.5, height=5, units="in", pointsize=14, res=200) # Für Publikation Schriftgröße sinnvoll setzen! http://civilstat.com/?p=557 plot(1:10) dev.off() # eps-äquivalente (Encapsulated Postscript, kann nachbearbeitet werden) postscript("versuch.eps", onepage=TRUE, horizontal=FALSE) plot(rnorm(10)) # wenn dir eps nichts sagt, einfach überspringen. dev.off() # Fortlaufende Nummerierung bei mehreren Bildern: %03d im Dateinamen png("Bild%d.png") # %03d hängt führende Nullen (leading zeros) vor par(bg=2) plot( c(6,9,0,2,8), type="h", lwd=7 ) plot( 1:8 ) # danach: dev.off() # sonst ist das letzte Bild noch leer! # Verschiedene Speichermöglichkeiten: dir.create("PNG_Test_Bilder") oldwd <- setwd("PNG_Test_Bilder") png("Test_A_%d.png") # ohne führende Nullen von 1:n durchnummeriert for(i in c(1:8, 837, 2087, 2333)) plot(i) # i ist nicht im Dateinamen! dev.off() png("Test_B_%4d.png") # mit Leerzeichen for(i in 1:13) plot(i) dev.off() png("Test_C_%04d.png") # mit Nullen for(i in 56:68) plot(i) dev.off() for(i in c(1:8, 837, 2087, 2333)) # mit i im Dateinamen { png(paste("Test_D_",i,".png", sep="")) plot(i) dev.off() } setwd(oldwd) unlink("PNG_Test_Bilder", recursive=T) # Seid vorsichtig mit diesem Befehl, der # kann auch das Skript, mit dem ihr es geschrieben habt, löschen! # Und alles mögliche andere! Wildcards nur nutzen, wenn ihr genau wisst, was die # auswählen! Und die gelöschten Dateien landen nicht im Papierkorb! # 4.12 Beidseitige y-Achsenbeschriftung ---------------------------------------- # Primär und Sekundärachse (Zweite Y-Achse mitbenutzen) # Lesetipp: http://rwiki.sciviews.org/doku.php?id=tips:graphics-base:2yaxes # Graphiken mit zwei unkorrelierten Achsen sind problematisch! # perceptualedge.com/articles/visual_business_intelligence/dual-scaled_axes.pdf # http://junkcharts.typepad.com/junk_charts/2006/06/illusion_of_suc.html # http://junkcharts.typepad.com/junk_charts/2006/05/the_crossover_l.html # Möglichkeit 1, günstig für gleiche y-Bereiche par(mar=c(2,4,2,4)) # wichtig: rechts mehr Platz machen a <- c(6,2,9,0,4) ; b <- c(8,7,1,4,6) ; d <-c(43,65,12,23,27) plot (a, type="l", las=1, ylab="Variable 1") lines(b, col=2) axis(4, 2:9, letters[1:8], col.axis=2, las=1) mtext("Variable 2", 4, 2.5, col=2) # mtext("Text", Achse, Abstand) points(4, 7, cex=2) # Y-Koordinaten immer von links ("f" geht nicht) # Bei ungleichen Bereichen muss auf linkes ylim normiert werden plot (a, type="l", las=1, ylab="Variable 1") lines(d * 9/65, col=3) axis(4, pretty(d)*9/65, pretty(d), col.axis=3, las=1) mtext("Variable 2", 4, 2.5, col=3) # Möglichkeit 2, da spart man sich die ganze Normierung: dev.off() # Schließt altes Graphikfenster werte <- seq(-6,6,.01) par(mar=c(2,4,3,4)) plot( werte, dnorm(werte), type="l", las=1, ylab="Dichtefunktion", main="Normalverteilung") # pnorm und dnorm werden im Kapitel 5 vorgestellt. par(new=T, xaxt="n") plot(werte, pnorm(werte), type="l", col=2, ylab="", xlab="", yaxt="n") axis(4, pretty(0:1), col.axis=2, las=1) mtext("kumulierte Wahrscheinlichkeit", 4, 2.5, col=2) legend("topleft", c("dnorm", "pnorm"), col=1:2, lty=1) abline(h=0.3, lwd=2) par()$usr # Graphikbereich ist jetzt der vom zweiten Plot! # 4.13 Achsen unterbrechen, Pakete installieren und laden ---------------------- # Cran Mirror auf Berlin setzen (Siehe Kap 10 für dauerhaftes Setting) options(repos='http://mirrors.softliste.de/cran') # Package plotrix installieren (einmalig), kann man anschließend auskommentieren # R > Pakete > Installiere Paket(e)... > CRAN > plotrix ODER: install.packages("plotrix") # offline Tipp: Zips der Pakete in R/Library speichern. # dann kann man auf einem anderen Rechner per USB-Stick ohne Internet arbeiten. # Jetzt das Paket laden (Nach jedem Start von R) library(plotrix) # Mit "Anführungsstrichen" ist auch OK # Breaks werden zum Plot hinzugefügt, bei Überlappung evt. Daten neuzeichnen plot(4:15, ylim=c(2,15)) axis.break(2, 2.9, style="slash") # Plot mit größeren Lücken gap.plot(c(rnorm(10)+4,rnorm(10)+20), gap=c(8,16),xlab="Index", ylab="Zufallszahlen",col=c(rep(2,10),rep(3,10)), ytics=c(3,4,5,19,20,21)) legend(12,6,c("High group","Low group"), pch=1, col=3:2) dev.off() # 4.14 mehrdimensionale Info in Graphiken -------------------------------------- # Farbe zeigt dritte Dimension: # Matrix: volcano[1:10, 1:10]; dim(volcano) image(volcano) # Punktdaten: install.packages("berryFunctions") library(berryFunctions) i <- c( 22, 40, 48, 60, 80, 70, 70, 63, 55, 48, 45, 40, 30, 32) j <- c( 5, 10, 15, 20, 12, 30, 45, 40, 30, 36, 56, 33, 45, 23) k <- c(175, 168, 163, 132, 120, 117, 110, 130, 131, 160, 105, 174, 190, 183) colPoints(i,j,k, cex=1.5, pch="+", add=FALSE) # Dichte der Daten zeigen: sunflowerplot par(mar=c(3,0,3,0)) sunflowerplot(1,1, xlim=c(1,20)) for (i in 2:20) sunflowerplot(rep(i,i), rep(1,i), xlim=c(1,20), add=T) title(main="sunflowerplot") # for - Schleifen wiederholen Operationen. Details in Kapitel 11. # Es geht hier erstmal um die Darstellung der Sonnenblumen. # Transparenzplots x <- rnorm(2000) # 2000 Zufallszahlen aus der Normalverteilung y <- rnorm(2000) # Siehe Kapitel 5 für Details. plot(x, y, col = rgb(0, 0, 0, alpha = 0.2), pch = 16) # kontinuierliche Dichte zeigen: hdr.boxplot.2d install.packages("hdrcde") # nur einmal require(hdrcde) x <- c(rnorm(200,0,1),rnorm(200,4,1)) y <- c(rnorm(200,0,1),rnorm(200,4,1)) par(mfrow=c(1,2)) plot(x,y, pch="+", cex=.5) hdr.boxplot.2d(x,y) # Kontinuierliches Histogramm install.packages("UsingR") library(UsingR) simple.violinplot(decrease ~ treatment, data=OrchardSprays, col="bisque", border="black") # 4.15 Dreidimensionales Plotten ----------------------------------------------- # einige Basic-Befehle x <- 1:10 ; y <- 1:10 ; z <- matrix(rnorm(100), ncol = 10) round(z, 2) filled.contour(x, y, z) contour(x, y, z) persp(x,y,z) # 3d-plot von allen Seiten betrachten # install.packages("rgl") # nur einmal zum downloaden und installieren. library(rgl) # in jeder Sitzung. t <- seq(0,30,0.01) ; x <- 1/pi*t ; y <- sin(t) ; z <- cos(t) open3d() # Fenster in Sichtweite ziehen plot3d(x,y,z, type = "l", xlab = "X", ylab = "Y", zlab = "Z") # mit der Maus klicken und ziehen. Cool, was? r3dDefaults x <- seq(-5,5,len=41) ; y <- x z <- outer(x,y,function(x,y){ifelse(x*x+y*y==0,NA, sin(3*sqrt(x*x+y*y))/sqrt(x*x+y*y))}) open3d() plot3d(x,y,z, type="l", xlab="X-Achse", ylab="Y-Achse", zlab="Z-Achse") # Persp benutzen ?volcano ; v <- volcano persp(1:nrow(v), 1:ncol(v), v, theta=135, phi=30, shade=0.75, border=NA) x <- y <- seq(-5,5,len=41) z <- outer(x,y,function(x,y){ifelse(x+y==0,NA,(x^2-2*x+3*y)/(x+y))}) for (i in 1:360) persp(x,y,z, theta=i, shade=0.75, border=NA, ticktype="detailed", expand=0.5) z2 <- outer(x,y, function(x,y) ifelse( x*x+y*y==0, NA, sin(3*sqrt(x^2+y^2))/sqrt(x^2+y^2) ) ) for (i in 1:360) persp(x,y,z2, theta=i, phi=i, shade=0.75, border=NA, ticktype="detailed",expand=0.5) persp(x, y, z, theta=30, phi=30, expand=0.5, col="lightblue") persp(x, y, z, theta=30, phi=30, expand=0.5, col="lightblue", ltheta=120, shade=0.75, ticktype="detailed", xlab="X", ylab="Y", zlab="Z") graphics.off() # schließt alle Graphikfenster x <- seq(-10, 10, length = 50) ; y <- x rotsinc <- function(x,y) { sinc <- function(x) { y <- sin(x)/x ; y[is.na(y)] <- 1; y } 10 * sinc( sqrt(x^2+y^2) ) } z <- outer(x, y, rotsinc) ; dim(z) par(bg = "white",mfrow=c(1,2),mar=rep(1.5,4)) persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue") title(sub=".")## work around persp+plotmath bug title( main = expression( z == Sinc(sqrt(x^2 + y^2)) ) ) persp(x, y, z, theta = 30, phi = 30, expand = 0.5, col = "lightblue", ltheta = 120, shade = 0.75, ticktype = "detailed", xlab = "X", ylab = "Y", zlab = "Z") dev.off() # Baumgrößen in 2D-darstellen -------------------------------- graphics.off() # bestehende Devices mit ihren Einstellungen schließen Orange str(Orange) # komischer Objekttyp Orange$Tree <- as.numeric(Orange$Tree) # factor mit anderen Zahlen... # Siehe auch Beispiele in ?Orange plot(Orange[Orange$Tree==1, 2:3], main="Orange Trees", xlim=range(Orange$age), ylim=range(Orange$circumference), type="o") for(i in 2:5 ) lines(Orange[Orange$Tree==i, 2:3], col=i, type="o") text(x=c(rep(1600,4), 1250), y=c(130,150,170,195,195), paste("Tree", 1:5), adj=1, col=1:5) # Falls gewünscht: für jeden Baum ein eigenes Plot, je mit gleicher Skalierung par(mfrow=c(2,3), mar=c(3.5,3,2,1), mgp=c(2,1,0)) for(i in 1:5 ) { plot(Orange[Orange$Tree==i, 2:3], main=paste("Tree Nr.", i), col=i, xlim=range(Orange$age), ylim=range(Orange$circumference), type="o") box("figure") } # Baumgrößen in 3D ------------------------------------------ open3d() plot3d(Orange$age, Orange$Tree, Orange$circumference, type="s", col=Orange$Tree) # Übersichtlicher ist es nicht unbedingt... Aber schön explorativ mit der Maus. # 4.16 Fehlerbalken (Error bars) ----------------------------------------------- # Funktionen für Konfidenzintervall definieren (Siehe Kap 12)... cil <- function(dat) return( t.test(dat, conf.level=.95)$conf.int[1] ) ciu <- function(dat) return( t.test(dat, conf.level=.95)$conf.int[2] ) # ... und anwenden: cil( rnorm(30, mean=5) ) # untere Grenze des 95%igen Konfidenzintervals # Integrierter Datensatz Iris (siehe Kapitel 7) head(iris) str(iris) # Werte zuordnen ( Vektoren mit Positionen der Fehlerbalken definieren ) mitte <- tapply(iris$Sepal.Length, iris$Species, mean)# Funktion mean anwenden unten <- tapply(iris$Sepal.Length, iris$Species, cil) # auf die Sepal.Length, oben <- tapply(iris$Sepal.Length, iris$Species, ciu) # getrennt nach Spezies # Barplot und x-Positionen der Balken x.values <- barplot(mitte, ylim=c(0,7), col="cyan") # Werte anschauen mit 3 Stellen (2 nach Komma) print( data.frame(x.values, mitte, unten, oben) , digits=3) # Fehlerbalken einfügen arrows(x.values, unten, x.values, oben, angle=90, code=3, length=0.3) # mit length lässt sich die Strichbreite einstellen. # Oder mit errbar im Paket Hmisc: install.packages("Hmisc") library(Hmisc) barplot(mitte, space=0, ylim=c(0,7)) ; axis(1, 0:3) errbar(1:3-.5, mitte, oben, unten, add=T) barplot(mitte, space=0, ylim=c(0,7)) ; axis(1, 0:3) errbar(1:3-.5, rep(NA,3), oben, unten, add=T) ; box() # Im Paket "gplots" gibt es die Funktion "plotCI" install.packages("gplots") library(gplots) ?plotCI # Example with confidence intervals and grid ( hh <- t(VADeaths)[, 5:1] ) ; ci.l <- hh * 0.85 ; ci.u <- hh * 1.15 barplot2(hh, beside=TRUE, legend=colnames(VADeaths), ylim=c(0, 100), col=c("lightblue", "mistyrose", "lightcyan", "lavender"), main="Death Rates in Virginia", font.main = 4, plot.grid=TRUE, sub="Faked 95 percent error bars", col.sub = "gray20", cex.names=1.5, plot.ci=TRUE, ci.l=ci.l, ci.u=ci.u,) browseURL("http://cran.r-project.org/doc/contrib/Lemon-kickstart/kr_ptline.R") # Auch plotrix hat eine Funktion: install.packages("plotrix") library(plotrix) plotrix::plotCI(1:3, mitte, ui=oben, li=unten, pch=1, slty="solid", scol=4) y <- runif(10) ; err.x <- runif(10) ; err.y <- runif(10) plotCI(1:10,y, err.y, pt.bg=2, pch=21, xlim=c(0,11)) plotCI(1:10,y, err.x, pt.bg=2, pch=21, err="x", add=TRUE) # 4.17 Fläche unter Graphen füllen --------------------------------------------- bspx <- c(1,3,4,5,7,9,10,13) bspy <- c(7,4,9,2,6,5,9,11) plot(bspx,bspy, ylim=c(0,15)) letzte <- length(bspx) polygon( c(bspx, bspx[letzte], bspx[1]) , c(bspy, 1, 1), col=2 ) # Einheitsganglinien mit Mittelwert und Konfidenzband v <- c(0,1,3,5,6,7,8,7,6,5,4,4,3,3,2,2,2,1,1,1,0,0,0,0)/30 ; lv <- length(v) set.seed(17) # gibt dem Zufallszahlengenerator einen Startpunkt. ( m <- matrix(v+runif(lv*10, 0, 0.13), nrow=lv) ) plot(m[,5], type="n", las=1, ylab="Ordinaten", xlab="Stunden nach Ereignisbeginn", main="Einheitsganglinie") for(i in 1:10) lines(m[,i]) cia=0 ; cib=0 for (i in 1:lv) { cia[i]=t.test(unlist(m[i,]), na.rm=T)$conf.int[1] cib[i]=t.test(unlist(m[i,]), na.rm=T)$conf.int[2] } cia ; cib polygon(c(1:lv,lv:1), c(cia, cib[lv:1]), col="orange", border="transparent") cic=0 ; cid=0 for (i in 1:lv) { cic[i]=t.test(unlist(m[i,]), conf.level = 0.7, na.rm=T)$conf.int[1] cid[i]=t.test(unlist(m[i,]), conf.level = 0.7, na.rm=T)$conf.int[2] } polygon(c(1:lv,lv:1), c(cic, cid[lv:1]), col=2, border="transparent") for(i in 1:10) lines(m[,i]) lines(apply(m, 1, mean, na.rm=T), col=3, lwd=3) par(lend="butt") legend("topright", c("Einzelne UHs","95% Konf. Int.", "70% Konf. Int.", "Mittelwert"), lwd=c(1,7,7,3),col=c(1,"orange",2,3)) mtext("10 Ereignisbasierte Unit Hydrographs sind zuwenig!",1,-2, adj=.4) # Einfügen von Rechtecken plot(1:10) rect(1,5,3,7, col="green") # polygon, segments, symbols, arrows, curve, abline, points, lines # http://addictedtor.free.fr/graphiques/RGraphGallery.php?graph=154 # SEHR EMPFEHLENSWERTE SEITE!!! (Siehe Source Code für die Befehle) # 4.18 Funktionen zeichnen ---------------------------------------------------- curve(x^3-3*x, -2, 2) curve(x^2-2, add = TRUE, col = "violet") plot(cos, xlim = c(-pi,3*pi), n = 1001, col = "blue") chippy <- function(x) sin(cos(x)*exp(-x/2)) curve(chippy, -8, 7, n=2001) curve(chippy, -8, -5) # Interferenz x <- seq(-pi,pi,len=1000) windows(record=T) par(mar=rep(0,4)) cool <- function (a) plot(a*sin(x), a*cos(x), asp=1, type="l") # Die for-Schleife zeichnet für jeddes i ein Bild. Mehr in Kap 11. for (i in 1:500/500) cool(c(i,1)) # Vorischt: höhere Rechen- und plot-zeit for (i in -600:300/500) cool(c(i,i-.43)) # Jetzt kann man mit Pg Up und Pg Dn die 901 Bilder durchklicken... # Oder die speichern und als GIF animieren... # 4.19 zooming in graphics ----------------------------------------------------- install.packages("berryFunctions") # mit meinem Paket --- require(berryFunctions) a <- rnorm(90); b <- rexp(90) plot(a,b, las=1) pointZoom(a,b,,1,40) d <- data.frame(a,b) class(d) plot(d) pointZoom(d) install.packages("playwith") # mit einer tollen interaktiven Geschichte --- require(playwith) ?playwith playwith( {plot( 1:10, rnorm(10) ) lines( (1:10) + 0.5, rnorm(10,1,3), col='red' ) }) install.packages("TeachingDemos") # mit einem weiteren Paket --- require(TeachingDemos) ?zoomplot # 4.20 und ein würdiger Abschluss des Kapitels --------------------------------- install.packages("onion") require(onion) data(bunny) p3d(bunny,theta=3,phi=104,box=FALSE) # 4.21 Übersicht der wichtigsten Graphikbefehle -------------------------------- # Noch to be ergänzt. Für Hinweise wäre ich sehr dankbar! # high-level plots (fangen neue Graphik an) plot(x, y) pairs(data.frame) coplot(a ~ b | c + d) qqnorm(x) qqline(x) qqplot(x, y) hist(x) dotchart(x, ...) image(x, y, z, ...) contour(x, y, z, ...) persp(x, y, z, ...) barplot(y) boxplot(y) curve() pie() # low level plots (fügen zur bestehenden Graphik hinzu) points() lines() # wie points, mit type="l" als default (spart Tipparbeit) text() abline() polygon() rect() legend() title() axis() -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 5: statistische Verteilungen ####################################### # Wahrscheinlichkeitsverteilungen (Probability distributions) # Verteilungen Parameter: # 5.1 diskret: Binomialverteilung Stichprobenumfang (n), Wahrsch. (p) # 5.2 diskret: Poissonverteilung Mittelwert (m) # 5.3 stetig: Normal / Gauss Mittelwert (m), Standardabweichung (sd) # 5.4 stetig: Exponentialverteilung Rate (r) # 5.5 stetig: Beta-Verteilung shape1 (a/alpha), shape 2 (b/beta) # 5.6 weitere Verteilungen # 5.7 Simulationen # Vorsilben (Prefixes): Beispiel: # d probability density function Wahrscheinlichkeitsfunktion dexp(...) # p cumulative probability function Verteilungsfunktion pbinom(...) # q quantiles of the distribution qnorm(...) # r random numbers generated from the distribution rpois(...) # 5.1 Diskret: Binomialverteilung ---------------------------------------------- # Beispiele: Torwandschießen; Erfolg = Treffer, Misserfolg = kein Treffer # Ziehen von Kugeln aus Urne; Erfolg = weiße Kugel, Misserfolg = schwarze Kugel # Relevant ist die Anzahl der Erfolge in n Versuchen # Wenn es um das Ergebnis eines einzelnen Versuches geht: Bernoulli-Verteilung # Werte definieren werte <- seq (from=0, to=30, by=1) # kurz: seq(0,30,1) # kürzer 0:30 werte # Binomial-Wahscheinlichkeits-Dichte-Funktion: y.dbinom <- dbinom(x=werte, size=10, prob=0.5) # 10 mal ziehen, plot(werte, y.dbinom) # Erfolgswahrscheinlichkeit gleich 0,5 ?dbinom # (Trefferquote ist 50 %) # öfter ziehen plot(werte, dbinom(werte, size=10, prob=0.5), ylim=c(0,0.25), pch=16, main="Binomialverteilung, Erfolgswahrs. = 0.5", xlab="Anzahl Erfolge") points(werte, dbinom(werte, 20, 0.5), ylim=c(0,0.25), pch=16, col=2) points(werte, dbinom(werte, 50, 0.5), ylim=c(0,0.25), pch=16, col=3) legend("topright", paste("n =", c(10,20,50)), title="Anzahl Versuche", pch=16, col=1:3, inset=0.02) # Erfolgsquote verändern plot(werte, dbinom(werte, 20, 0.85), ylim=c(0,0.25), pch=16, main="Binomialverteilung, Stichprobenumfang n = 20", xlab="Anzahl Erfolge") points(werte, dbinom(werte, 20, 0.5), ylim=c(0,0.25), pch=16, col=2) points(werte, dbinom(werte, 20, 0.2), ylim=c(0,0.25), pch=16, col=3) legend("topright", paste("prob =",c(.85,.5,.2)), title="Erfolgswahrsch.", pch=16, col=1:3, inset=0.02) n <- 8 # Anzahl Münzwürfe: wie wahrscheinlich x mal Kopf? plot(0:n, dbinom(0:n, n, 0.5), pch=16, xlab="x = Anzahl 'Kopf'", las=1, main=paste(n, "-facher Münzwurf", sep=""), ylab="Wahrsch. für x-fach Kopf") abline(h=0.025, col=6) # Bei 8-maligem Werfen kommt es in 3% der Versuche vor, dass nur 1 mal Kopf # auftritt. Wenn jemand 8 mal wirft, und nur 1 mal Kopf (bzw. Zahl) auftritt, # kann ich dennoch nicht annehmen, dass die Münze gezinkt ist (bei 2.5%-Grenze). # Mord in Palermo / Werwölfe werte <- 0:10 windows(record=T) for (i in 0:40) { plot(werte, dbinom(werte, i, 1/8), ylim=c(0,1), xlab="x", main=paste("Wahrscheinlichkeit, Mörderkarte x mal zu bekommen\nbei",i,"Runden")) legend("topright", "1 von 8 Karten Mörder") } # Die Zufallsvariable X sei 'Anzahl Sechser beim viermaligen Würfeln'. # Die Einzelwahrscheinlichkeiten der fünf möglichen Realisationen sind # P(X=0) = (5/6)^4 = 0.48225 # P(X=1) = 4(1/6) (5/6)^3 = 0.38580 # P(X=2) = 6(1/6)^2(5/6)^2 = 0.11524 # P(X=3) = 4(1/6)^3(5/6) = 0.01543 # P(X=4) = (1/6)^4 = 0.00077 dbinom(0:4, 4, 1/6) plot(0:4, dbinom(0:4, 4, 1/6), pch=16) # Zufallszahlen ziehen rbinom(n=40, size=10, prob=0.5) # 5.2 Diskret: Poissonverteilung ----------------------------------------------- # Zähldaten, z.B. Anzahl Telefonanrufe pro Stunde im Callcenter # oft auch bei geringen Wahrscheinlichkeiten für große Werte (p klein, n groß) # Beispiel: radioaktiver Zerfall; Aus einer sehr großen Anzahl von Atomen # zerfällt in einer Zeiteinheit nur ein sehr kleiner Anteil der Atome. # Dieser Zerfall ist zufällig und unabhängig von den schon zerfallenen Atomen. # Binomial-Wahscheinlichkeits-Dichte-Funktion # lambda ist mittleres Auftreten von Ereignissen plot(0:20, dpois(0:20, lambda = 0.5), pch=16) points(0:20, dpois(0:20, lambda = 1), pch=16, col=2) points(0:20, dpois(0:20, lambda = 2), pch=16, col=3) points(0:20, dpois(0:20, lambda = 5), pch=16, col=4) points(0:20, dpois(0:20, lambda =10), pch=16, col=5) # Zufallszahlen ziehen rpois(n=5, lambda=0.8) # 5.3 Stetig: Gauss-(Normal)-verteilung ---------------------------------------- # analog zum Vorgehen bei den stetigen Verteilungen werte <- seq (from = -10, to = 10, by = 0.01) head(werte) plot(werte) plot(werte, dnorm(werte, mean = 5, sd = 1.0)) windows(record=T) # Speichere Bilder, sodass mit Pg Up und Pg Dn durchklickbar for(i in 1:10) # führe für jedes i folgende Zeilen aus: { plot(-20:20, dnorm(-20:20, 0, sd=i ), main=paste("St. Abw. =", i), xlab="x", ylab="p(x)", type="o") abline(v=c(0+i, 0-i)) } # Mehr zu For-Schleifen in Kapitel 10 dev.off() # schließe Graphikfenster # Zufallszahlen als Spalte zuf.zahl <- rnorm(10, mean = 5.0, sd = 0.5) data.frame(zuf.zahl) rnorm(10) # Plotten von Zufallszahlen der Standardnormalverteilung (mean=0, sd=1) plot(rnorm(10)) plot(rnorm(1000), pch=16, cex=0.5) plot(rnorm(500,mean=0,sd=1),rnorm(500,mean=0,sd=1), pch=16,cex=0.5,abline(v=0, h=0),xlim=c(-4,4), ylim=c(-4,4)) # Variationskoeffizient x <- -1:130 plot(x, dnorm(x,5,2), type="l", main="Unsinn des Variationskoeffizienten", ylab="dnorm(x,5,2) | dnorm(x,100,2)") lines(x, dnorm(x,100,2)) text(10, 0.15, "CV = sd/mean = 0.4", adj=0) text(105, 0.15, "CV = 0.02",adj=0) # VK also nur bei Vergleichen zweier Gruppen mit ähnlichem Mittelwert sinnvoll set.seed(123) # Gibt dem "Zufallszahlen"-Generator den Startpunkt, sodass # jeder Lauf die gleiche Zahlen ergibt. d <- rnorm(29); hist(d) # Homer's Favorite Food - normalverteilt angenähert... par(mar=c(0,0,0,0), pch="." ) plot(10,10, xlim=c(0,20), ylim=c(0,20)) points( rnorm(100000, 10, 2) + 5*sin(seq(0, 2*pi, len=100000)), rnorm(100000, 10, 2) + 5*cos(seq(0, 2*pi, len=100000)) ) # Points-Befehl häufiger wiederholen... # Anwendung kumulierter Wahrscheinlichkeit (pnorm) # Umfrage zur Körpergröße von Personen # Mittelwert 170 cm, Standardabweichung 8 cm in Normalverteilung graphics.off() plot(150:190, dnorm(150:190, mean=170, sd=8), type="l") ; #abline(h=0:5/100) par(new=T); plot(150:190,pnorm(150:190,170,8), type="l", axes=F, col=2, ylab="") axis(4,pretty(0:1), col.axis=2) ; abline(v=c(160,185, 165.8), col=c(4,4,3)) for(h in 1:9*.1) lines( c(qnorm(h,mean=170, sd=8),200), rep(h,2), col=2) # Wahrscheinlichkeit, dass eine zufällig gewählte Person kleiner als 160 ist pnorm(160, mean=170, sd=8) # Wahrscheinlichkeit, dass eine zufällig gewählte Person größer als 185 ist 1 - pnorm(185, mean=170, sd=8) # Wahrscheinlichkeit, dass eine Person zwischen 160 und 185 groß ist pnorm(185, mean=170, sd=8) - pnorm(160, mean=170, sd=8) # Mit 30%iger Wahrscheinlichkeit ist eine Person kleiner als ... qnorm(.3, mean=170, sd=8) # 5.4 Stetig: Exponentialverteilung -------------------------------------------- # Beispiel: Zeitabstand zwischen zwei Erdbeben / Naturkatastrophen # Beispiel: Lebensdauer von elektronischen Bauelementen; # Die Wahrscheinlichkeit, dass ein älteres Bauteil noch t Tage hält, # muss genauso groß sein, wie die, dass ein neues Bauteil t Tage hält. # Die "Ausfallrate" ist konstant (nur für positive Werte). # analog zum obigen Vorgehen werte <- seq (from = 0, to = 1, by = 0.001) plot(werte, dexp(werte, rate = 3), type="l", main="Exponentialverteilung") lines(werte, dexp(werte, rate = 5), col=2) text(0.3, 2.5, "rate=5", col=2) ; text(0.1, 1.5, "rate=3") # Zufallszahlen rexp(8, rate = 3) # 5.5 Stetig: Beta-Verteilung -------------------------------------------------- # Zwischen 0 und 1; wird viel in Bayes-Statistik verwendet werte <- seq (from = 0, to = 1, by = 0.001) plot(werte, dbeta(werte, shape1=0.5, shape2=5)) # Zufallszahlen rbeta(8, shape1=3, shape2=1) # grafisch dargestellt browseURL("http://www.uni-konstanz.de/FuF/wiwi/heiler/os/vt-index.html") # Siehe auch library("berryFunctions"); ?betaPlot # Normalverteilungen beschreiben Werte nicht immer richtig! (meistens nicht): set.seed(2) ; d <- rbeta(200, 2,4)*350 + 80 hist(d, col=3, breaks=20) text(350,25, paste("mean =", round(mean(d),2),"\nsd =",round(sd(d),2)), adj=1) par(new=T) plot(80:400, dnorm(80:400, mean(d),sd(d)), type="l", lwd=3, axes=F, ann=F) # wo die Normalverteilung die meisten Werte erwartet, sind weniger! # 5.6 weitere Verteilungen ----------------------------------------------------- werte <- seq(-3, 3, .01) plot(werte, dunif(werte, -1, 1), type="l") # density uniform distribution lines(werte, dnorm(werte), col=2) # "-" normal "-" plot(werte, punif(werte, -1, 1), type="l") # probability distribution: uniform lines(werte, pnorm(werte), col=2) # pd: normal (cumulative probability) # Plotten von Zufallszahlen einer Gleichverteilung: runif(n, von, bis) # alle Werte (zwischen 0 und 1) sind gleich wahrscheinlich (uniform) plot(runif(10)) # Random numbers from UNIForm distribution plot(runif(1000), pch=16, cex=0.5) # Hier eine Auswahl weiterer Verteilungen, mit Dank an Boris Schröder: rnorm(n, mean=0, sd=1) # Gaussian (normal) rexp(n, rate=1) # exponential rgamma(n, shape, scale=1) # gamma rpois(n, lambda) # Poisson rweibull(n, shape, scale=1) # Weibull rcauchy(n, location=0, scale=1) # Cauchy rbeta(n, shape1, shape2) # beta rt(n, df) # 'Student' (t) rf(n ,df1, df2) # Fisher-Snedecor (F) rchisq(n, df) # Pearson (Chi^2) rbinom(n, size, prob) # binomial rgeom(n, prob) # geometric rhyper(nn, m, n, k) # hypergeometric rlogis(n, location=0, scale=1) # logistic rlnorm(n, meanlog=0, sdlog=1) # lognormal rnbinom(n, size, prob) # negative binomial runif(n, min=0, max=1) # uniform rwilcox(nn, m, n) # Wilcoxon's statistics rsignrank(nn, n) # Wilcoxon's statistics browseURL("http://cran.r-project.org/doc/manuals/R-intro.pdf") # Kapitel 8 Probability distributions (2013-03-01 Seite 41 PDF / 35 print) browseURL("www.bb-sbl.de/tutorial/verteilungen") # Eine ganze Reihe (Extremwert-)verteilungen an Daten fitten und analysieren: # package extremeStat (on github), siehe Kapitel 15.7 # 5.7 Simulationen ------------------------------------------------------------- # Wenn man nicht berechnen kann oder will, kann man oft auch simulieren. # z.B. die Verteilung der Summenzahl dreier Würfeln: f <- function() sample(1:6, 1e7, replace=TRUE) erg <- f() + f()+ f() # Vektorisieren, wann immer es geht plot(table(erg)/1e7, las=1, main="empirische Wahrscheinlichkeit für erg Anzahl Augen mit 3 fairen Würfeln") # z.B. die Wahrscheinlichkeit, drei Mädchen hintereinander zu bekommen: gender <- t(sapply(1:1e5, function(x) sample(0:1, 3, TRUE) )) head(gender) plot(table(rowSums(gender))/1e5, las=1, main="Anzahl Mädchen bei 3 Kindern") # gilt nur, wenn # - Geschlecht von dem der Geschwister unabhängig ist # - die Wahrscheinlichkeit für ein Geschlecht 50% beträgt # - kein Survivorship Bias besteht (Mädchen öfter abgetrieben als Jungs zB) # - ... -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 6: Lagemaße, Boxplot, Histogramm, qq-Plot ########################## # (exploratory data analysis, EDA) # 6.1 Daten # 6.2 Histogramme # 6.3 Lagemaße # 6.4 Boxplots (und warum man sie nicht so oft verwenden sollte) # 6.5 QQ-Plots # 6.1 Daten -------------------------------------------------------------------- # hydraulische Leitfähigkeit (Ksat) in Tiefe A und B set.seed(28) # set.seed sorgt dafür, dass jeder Lauf die gleichen Zahlen ergibt. KsA <- round(rexp(40, .02), digits=2) KsB <- round(rexp(40, .04), digits=2) KsA # Hier habe ich 40 Zufallszahlen der Exponentialverteilung gewählt. KsB Ks <- data.frame(KsA, KsB) ; Ks # 6.2 Histogramme -------------------------------------------------------------- hist(KsA, col=3, breaks=10) # zwischen 0 und 20 liegen 15 Werte, usw. histdata <- hist(KsB, col=2) histdata rm(histdata) # wieder aus dem Workspace löschen par(mfrow=c(1,2)) hist(KsA, cex.axis=0.7, breaks=20, col=3) hist(KsB, cex.axis=0.7, col=2) par(mfrow=c(1,1)) # Oder in einem Plot: hist(KsA, border=3, col=rgb(0,1,0, alpha=.2)) # Alpha für Teiltransparenz hist(KsB, border=2, col=rgb(1,0,0, alpha=.2), add=T); box() legend("topright", c("KsA","KsB"), fill=rgb(0:1,1:0,0, alpha=.2), border=3:2 ) # Auswirkung der Anzahl Breaks: ?volcano hist(volcano, breaks=5, main="5", ylim=c(0,2000), xlim=c(50,200)) hist(volcano, breaks=10, main="10", ylim=c(0,2000), xlim=c(50,200)) hist(volcano, breaks=15, main="15", ylim=c(0,2000), xlim=c(50,200)) hist(volcano, breaks=40, main="40", ylim=c(0,2000), xlim=c(50,200)) hist(volcano, breaks=80, main="80", ylim=c(0,2000), xlim=c(50,200)) hist(volcano, breaks=150, main="150", ylim=c(0,2000), xlim=c(50,200)) # Rand nur außenrum: h <- hist(volcano, col=3, border=NA) polygon(x=c(rep(h$breaks, each=2)), y=c(0, rep(h$counts, each=2), 0), lwd=2 ) # 6.3 Lagemaße ----------------------------------------------------------------- # Minimalwert, Maximalwert, Wertespanne min(KsA) max(KsA) range(KsA) # arithmetisches Mittel vs Median mean(KsA) # 54 mm/h median(KsA) # 50% der Werte liegt unter 32 mm/h, 50% der Messwerte sind größer # Der Mittelwert wird von den wenigen sehr hohen Werten hochgezogen. # Der Median ist ausreißerunabhängig. (Wobei hohe Ksatwerte keine Messfehler # sind, also nicht wirklich als Ausreißer zu bezeichnen sind.) # Beide Maßzahlen für die mittlere Größe einer Variable haben auch # ein Maß für die Streuung: Standardabweichung (sd) und median Abweichung (mad) sd(KsA) # 60 # Mit mean und sd kann jeder die Verteilung nachvollziehen: install.packages("berryFunctions"); library("berryFunctions") normPlot(mean(KsA), sd(KsA), ylim=c(0, 0.02), cum=F) hist(KsA, breaks=10, freq=F, add=T, col=2) # Die Verteilung wird mit den beiden Parametern völlig falsch beschrieben. # Mittelwert und Stabw sind NUR für normalverteilte Daten sinnvoll (siehe Kap 9) # MAD: Median der absoluten Abweichungen vom Median (median absolute deviation) # wird normalerweise normiert; damit das nicht passiert: constant = 1 mad(KsA, constant=1) # durchnittlich liegen die Werte 24 mm vom median entfernt. # Quantile = Percentile, x% der Werte unter Quantil quantile(KsA) # 75% der Werte liegt unter 70 mm/h, dennoch gibt es Werte bis zu 296! # 25, 50 und 75% werden Quartile (Viertelbereiche) genannt, Q1, Q2 und Q3 # InterQuartilsDistanz: Abstand zwischen erstem (25%) und drittem (75%) Quartil IQR(KsA) # IQR = Inter Quartil Range, auch Fourth-spread # 50 % der Werte liegen zwischen Q1 und Q3 mit einer Breite von 54 mm/h # IQR entspricht der Streungsbreite ohne Extremwerte. Im Boxplot (siehe 6.4) # wird ein Wert als Ausreißer gesehen, wenn er 1.5*IQR über Q3 / unter Q1 liegt. # Fünf-ZahlenMaß: Min, 1.Quartil, Median, 3.Quartil, Max fivenum(KsA) ?boxplot.stats # Section Details erklärt, warum quantile und fivenum Q1 und Q3 # unterschiedlich herausgeben # Spalten vergleichen: Übersicht einiger Kennzahlen summary(KsA) # 9-Zahlenmaß: Median, Quartile (Fourth), Oktile (Eighth), Hexadezile, Range quantile(KsA, prob=c(0, 1/16, 1/8, 1/4, 1/2, 3/4, 7/8, 15/16, 1)) # Quantile kann man mit mehreren Methoden abschätzen: quantile(KsA, prob=c(0.90, 0.95, 0.99, 1), type=1) quantile(KsA, prob=c(0.90, 0.95, 0.99, 1), type=2) # in Kap 11.5 gibts eine systematische Analyse # EMPIRISCHE kumulative Verteilungsfunktion plot(ecdf(KsA), verticals=T, do.points=F) # 6.4 Boxplots ----------------------------------------------------------------- # Auch Box-Whisker-Plot # Whiskers: Maximalwert oder, wenn Ausreisser vorhanden, 1.5*IQR (ungefähr 2*sd) boxplot(KsA) # sind aber nicht wirklich Ausreißer, also lieber: boxplot(KsA, range=0) axis(1, c(.5,1,1.5)) # um zu entscheiden, wo Text, Pfeile, etc hin soll. arrows(.7, 100, .98, 160, col=2, lwd=2) plot(sort(KsA), pch=16); points(sort(KsB), col=2, pch=22) Ks <- data.frame(KsA, KsB) ; head(Ks) boxplot(Ks, range=0) # Notch (5%-Vertrauensintervall des Median, bei Statistikern umstritten!) boxplot(KsA, notch=T, xlab="KsA", ylab="Ksat [mm/h]", col=3, range=0) # Warnmeldung: einige notches liegen außerhalb der hinges ('box'): # evtl. notch=FALSE setzen -> zeigt, dass Daten breit gestreut sind. # Mittelwert in Boxplot einzeichnen boxplot(mean(KsA), add=T, border="red") # add=T: add boxplot to current plot # Zeichnet einen weiteren Boxplot, bestehend aus nur einem Wert, hinein. # Lagemaße einzeichnen abline(h=quantile(KsA, prob=c(1/16,1/8,1/4,1/2,3/4,7/8,15/16)), col ="blue") # Mehrere Datensätze in ein Fenster boxplotten boxplot(KsA, KsB, .8*KsA^1.2, notch=T, col=2:4) boxplot(Ks, notch=T, col=2:3) # automatische Beschriftung an der x-Achse # Mittelwerte in mehreren Boxen einzeichnen (mit Sternchen) a <- as.data.frame(matrix(rnorm(8*5), nrow=8, ncol=5)) bp <- boxplot(a) m <- apply(a, 2, mean) # wende die funktion mean spaltenweise (2) an. --> Kap.11 # Falls nötig: na.rm=T hinter mean: remove missing data (NA) points(1:5, m, pch=8, col="red", cex=1.5) # Um auch das mit Boxplots hinzuzufügen, muss m ein data.frame sein. m ; class(m); is.vector(m) # Sieht aus wie ein dataframe, ist aber ein Vektor! ma <- as.data.frame( t(m) ) # t = transpose: Zeile <-> Spalte ma ; class(ma) boxplot(ma, add=TRUE, border="red") # Spalten vergleichen: Boxplots boxplot(KsA, KsB, names=c("Ks A", "Ks B"), notch = T, ylab = "Ks [mm/h]", col = "grey", main = c("Ks der beiden Tiefen","")) # Mittelwert addiert boxplot(data.frame(t(apply(Ks, 2, mean))), add=TRUE, border=2, names=c("",""), main=c("","arithmetisches Mittel"), col.main="red", cex.main=0.8, notch=T) # Allerdings verstecken Boxplots die zugrundeliegende Verteilung der Daten. # Man sieht nur den Median und die Quartile, graphisch sehr ansprechend, aber # zur Untersuchung von Datenverteilungen ungeeignet. Siehe dieses Beispiel: set.seed(007) ; dontuseboxplots <- rbeta(100, shape1=2, shape2=4) X11() # Ordentliches Graphikfenster, falls du in Rstudio arbeitest op <- par(mfrow=c(3,1)) boxplot(dontuseboxplots, horizontal=T) title(main="eine leicht rechtsschiefe Normalverteilung, richtig?") hist(dontuseboxplots, breaks=20, col=8, main="") title(main="Nichts da: innerhalb des Boxes sind die Werte fast gleichverteilt!") plot(density(dontuseboxplots), xlim=range(dontuseboxplots), main="") title(main="Spannend ist auch eine KernDichteSchätzung") # oder dieses: par(mfrow=c(4,1), mar=c(2,2,1,1)) set.seed(42) ; dub1 <- c(rnorm(800,5,1), rnorm(200,9,0.5)) dub2 <- rbeta(1000, 6, 50)*39+1.2 # dub: Don't Use Boxplots (unwisely) boxplot(dub2, col=4, notch=T, ylim=c(1,12), horizontal=T) boxplot(dub1, col=3, notch=T, ylim=c(1,12), horizontal=T) title(main="Die sind sehr änhlich, nicht wahr?", line=-1, adj=0.9) hist(dub2, breaks=30, xlim=c(1,12), col=4, main=""); box() hist(dub1, breaks=30, xlim=c(1,12), col=3, main=""); box() title(main="Oh, doch nicht.", line=-1, adj=0.9) par(op) # Boxplots machen nur Sinn, wenn man mehr als zwei Datensätze mit gleicher # zugrundeliegender Verteilung in einem Plot vergleichen möchte. # 6.5 QQ-Plots ----------------------------------------------------------------- # qqnorm: Vergleich Datensatz zur Normalverteilung qqnorm(KsA, main = "Ks_A") qqline(KsA) # Punkte weit weg von der Linie --> Nicht normalverteilt # Gängig für Ksat-Werte, liegt hier natürlich auch an der Wahl der Daten plot(sort(KsA)) # das ist letztendlich, was qqnorm macht... qqnorm(KsB, main = "Ks_B") qqline(KsB) qqplot(KsA, KsB) # qqplot: Vergleich zweier (Datensätze) gegeneinander # Ich verwende eher Histogramme mit möglichst vielen breaks (in den einzelnen # Klassen sollten trotzdem viele Werte drin sein), um zu sehen, ob Daten # normalverteilt sind. # Siehe auch Tests auf Normalverteilungen in Kap 9. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 7: Große Datensätze: iris ########################################## # 7.1 Datensatz # 7.2 Subsets (Teildatensätze, indizieren) # 7.3 Graphiken # 7.4 EDA - Maßzahlen, Boxplots # 7.5 Histogramme, QQ-Plots # 7.1 Datensatz ---------------------------------------------------------------- # Integrierter Datensatz mit Messungen von Kronblättern (Petalen;oben; oft groß) # und Kelchblättern (Sepalen; unten; meist kleiner) verschiedener Iris Spezies iris # Sepalen bei Schwertlilien größer als Petalen class(iris) str(iris) summary(iris) pairs(iris, col=iris$Species) library(psych) pairs.panels(iris[,1:4]) # 7.2 Subsets (Teildatensätze, indizieren) ------------------------------------- # Anzeige + Verarbeitung ausgewählter Daten (Siehe Kapitel 3) iris$Petal.Length # Spalte "Petal.Length" als Vektor iris["Petal.Length"] # Spalte "Petal.Length" als Spalte iris[1:50,"Petal.Length"] # Zeilen 1 bis 50 der Spalte "Petal.Length" iris[iris$Species == "setosa",] # Datensatz für die Species Iris setosa iris$Petal.Length[iris$Species=="virginica"] # Petal.Length von Iris virginica # 7.3 Graphiken ---------------------------------------------------------------- # Petal.Length (y) gegen Petal.Width (x) plot(iris$Petal.Width, iris$Petal.Length, main = "Iris Petal-Dimensionen", xlab = "Breite der Petalen [cm]", ylab = "Länge der Petalen [cm]", col = ifelse(iris$Species=="setosa", "red", "blue" )) # allen drei Arten verschiedene Farben zuordnen plot(iris$Petal.Width, iris$Petal.Length, col=iris$Species) plot(sort(iris$Petal.Width), sort(iris$Petal.Length), col=iris$Species) # allen drei Arten verschiedene ausgewählte Farben zuordnen plot(iris$Petal.Width, iris$Petal.Length, col=ifelse(iris$Species == "setosa", "red", ifelse(iris$Species == "versicolor", "blue", "green" ))) # Zuordnungen zu Kürzeln für schnelles Plotten xl <- "Breite der Petalen [cm]" ; yl <- "Länge der Petalen [cm]" sl.seto <- iris$Sepal.Length[iris$Species == "setosa"] sw.seto <- iris$Sepal.Width [iris$Species == "setosa"] pl.seto <- iris$Petal.Length[iris$Species == "setosa"] pw.seto <- iris$Petal.Width [iris$Species == "setosa"] mn.seto <- "Iris Petalen\nI. setosa" sl.vers <- iris$Sepal.Length[iris$Species == "versicolor"] sw.vers <- iris$Sepal.Width [iris$Species == "versicolor"] pl.vers <- iris$Petal.Length[iris$Species == "versicolor"] pw.vers <- iris$Petal.Width [iris$Species == "versicolor"] mn.vers <- "Iris Petalen\nI. versicolor" sl.virg <- iris$Sepal.Length[iris$Species == "virginica"] sw.virg <- iris$Sepal.Width [iris$Species == "virginica"] pl.virg <- iris$Petal.Length[iris$Species == "virginica"] pw.virg <- iris$Petal.Width [iris$Species == "virginica"] mn.virg <- "Iris Petalen\nI. virginica" # Anmerkung: mit der Funktion by() ließen sich einige Zuordnungen umgehen. # mehrere Graphiken auf einem Blatt: relative Größen layout(matrix(1:3, 1, 3), widths=c(5, 5, 5)) plot(pw.seto, pl.seto , main=mn.seto, xlab=xl, ylab=yl, ylim=c(1,7)) plot(pw.vers, pl.vers , main=mn.vers, xlab=xl, ylab=yl, ylim=c(1,7)) plot(pw.virg, pl.virg , main=mn.virg, xlab=xl, ylab=yl, ylim=c(1,7)) # mehrere Graphiken auf einem Blatt: absolute Größen (in cm) # zB. für quadratische plots. Grafikfenster ausreichend groß ziehen! layout(matrix(1:3, 1 ,3), widths=lcm(c(5, 5, 5)), heights= lcm(5)) plot(pw.seto, pl.seto , main=mn.seto, xlab=xl, ylab=yl, ylim=c(1,7)) plot(pw.vers, pl.vers , main=mn.vers, xlab=xl, ylab=yl, ylim=c(1,7)) plot(pw.virg, pl.virg , main=mn.virg, xlab=xl, ylab=yl, ylim=c(1,7)) # Zurücksetzen der Graphik dev.off() # 7.4 EDA - Maßzahlen, Boxplots ------------------------------------------------ # 5-Zahlenmaß + mean für jeden Parameter, nach Iris-Arten getrennt summary(iris[iris$Species == "setosa",]) summary(iris[iris$Species == "versicolor",]) summary(iris[iris$Species == "virginica",]) # Boxplot-Vergleiche (zwischen den 3 Iris-Arten) pro Parameter par(mfrow = c(2,2)) boxplot(sl.seto, sl.vers, sl.virg, notch = T, ylab = "Länge der Sepalen [cm]", names = c("I.setosa", "I.versicolor", "I.virginica"), ylim=c(0,8)) means <- data.frame(t(c(mean(sl.seto),mean(sl.vers),mean(sl.virg)))) boxplot(means, add=TRUE, border=2, names=c("", "", "")) boxplot(sw.seto, sw.vers, sw.virg, notch = T, ylab = "Breite der Sepalen [cm]", names = c("I.setosa", "I.versicolor", "I.virginica"), ylim=c(0,8)) means <- data.frame(t(c(mean(sw.seto),mean(sw.vers),mean(sw.virg)))) boxplot(means, add=TRUE, border=2, names=c("", "", "")) boxplot(pl.seto, pl.vers, pl.virg, notch = T, ylab = "Länge der Petalen [cm]", names = c("I.setosa", "I.versicolor", "I.virginica"), ylim=c(0,8)) means <- data.frame(t(c(mean(pl.seto),mean(pl.vers),mean(pl.virg)))) boxplot(means, add=TRUE, border=2, names=c("", "", "")) boxplot(pw.seto, pw.vers, pw.virg, notch = T, ylab = "Breite der Petalen [cm]", names = c("I.setosa", "I.versicolor", "I.virginica"), ylim=c(0,8)) means <- data.frame(t(c(mean(pw.seto),mean(pw.vers),mean(pw.virg)))) boxplot(means, add=TRUE, border=2, names=c("", "", "")) par(mfrow = c(1,3)) boxplot(iris[iris$Species=="setosa",1:4], ylim=c(0,8), main="Iris setosa") boxplot(iris[iris$Species=="versicolor",1:4],ylim=c(0,8),main="Iris versicolor") boxplot(iris[iris$Species=="virginica",1:4], ylim=c(0,8), main="Iris virginica") par(mfrow = c(1,1)) # Zusammenhänge zwischen Elemente in großen Datensätzen pairs(iris, pch=16, cex=0.8, col=ifelse(iris$Species=="setosa", "red", ifelse(iris$Species=="versicolor", "blue", "green"))) # 7.5 Histogramme, QQ-Plots ---------------------------------------------------- # Histogramme des Parameters Sepal.Length par(mfrow=c(1,3)) sl <- "Länge der Sepalen [cm]" hist(sl.seto, xlab=sl, ylab = "Häufigkeit", main = "I. setosa", xlim=c(4,8), ylim=c(0,18), breaks=seq(4, 8, 0.25)) hist(sl.vers, xlab=sl, ylab = "Häufigkeit", main = "I. versicolor", xlim=c(4,8), ylim=c(0,18), breaks=seq(4, 8, 0.25)) hist(sl.virg, xlab=sl, ylab = "Häufigkeit", main = "I. virginica", xlim=c(4,8), ylim=c(0,18), breaks=seq(4, 8, 0.25)) # QQ-Plots des Parameters Sepal.Length mit eingezeichneten QQ-Linien qqnorm(sl.seto, main = "I.setosa") qqline(sl.seto) qqnorm(sl.vers, main = "I.versicolor") qqline(sl.vers) qqnorm(sl.virg, main = "I.virginica") qqline(sl.virg) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 8: Bayes-Statistik und -Hypothesentests ############################ # 8.1 Paket: Bolstad # 8.2 Urnenmodell # 8.3 # 8.4 Wasserqualität # 8.5 Hypothesentests # 8.1 Paket: Bolstad ----------------------------------------------------------- # R > Pakete > Installiere Paket(e)... > CRAN > Bolstad # oder kurz: install.packages("Bolstad") # Paket Downloaden, entpacken, installieren # Danach auskommentieren, muss nur einmal ausgeführt werden! library(Bolstad) # lädt das Paket, muss in jeder Sitzung geschehen # Für Binomial sampling with a discrete prior steht folgende Funktion bereit: ?binodp(x,n, pi=NULL, pi.prior=NULL, n.pi=10) # 8.2 Urnenmodell -------------------------------------------------------------- # Binomialverteilung, diskreter Prior # n = 5 Kugeln rot/grün; 6 gleichwahrsch. Hypothesen über Anzahl roter Kugeln # 1 rote gezogen (Erfolg) -> Funktion binodp (Seite 5 Bolstad Manual) binodp(1, 1, pi = rep(1/6, 6), pi.prior=NULL, n.pi=6 ) # 8.3 Mittelwertschätzung ------------------------------------------------------ # Inferenz: Schluß von einer Stichprobe auf die Grundgesamtheit # Schätzung des Mittelwertes unter Berücksichtigung von Vorwissen / Schätzung # Berechnung der Likelihood und des Posteriors eines jeden Wertes # 5 Hypothesen des Mittelwertes des Gewichts von Studentinnen in Potsdam mu <- c(55, 60, 64, 66, 73) # mu-Hypothesen prior <- rep(0.2, 5) # jede ist gleichwahrscheinlich richtig stichprobe <- c(72, 65, 60, 71, 70, 60, 59) Bolst <- normdp(x=stichprobe, sigma.x=sd(stichprobe), mu=mu, mu.prior=prior) # Plot nicht vergessen anzuschauen 😉 Bolst round(Bolst$posterior*100,2) # 0.00 2.71 45.62 51.58 0.09 # Gegeben diese Stichprobe, dass sind die Wahrscheinlichkeiten, dass die # jeweilige Hypothese richtig ist. # In diesem Fall würde man in der Realität kontinuierlich rechnen lassen: normgcp(x=stichprobe, sigma.x=sd(stichprobe), density="uniform", params=c(45,80), n.mu=80) # Der Posterior wird nur für n.mu diskrete Werte ausgegeben. # 8.4 Wasserqualität ----------------------------------------------------------- # Water Quality: n=116 water samples; y=17 samples contaminated. # Binomialverteilung (n=116, pi) (siehe Kap. 5) # pi = true probability that a water sample is contaminated # posterior distribution of pi given y with a beta(l,4) prior for pi binobp(17, 116, a=1, b=4) binobp # zeigt die zugrundeliegende Funktion (Siehe Kap 12) # Frequentist estimator (Erfolgswahrscheinlichkeit) = Zahl Erfolge / Samples ( pi.f <- 17/116 ) # = 0.09 # normal approximation to the posterior distribution g(pi|y). werte <- seq(0,1, len=10000) plot(werte ,dnorm(werte, mean=0.1487603, sd=0.0322173), type="l", ylim=c(0,14), main="n=116; y=17; beta(1,4)-prior", ylab="Density", xlab="pi") # 95% credible interval for pi with the normal approximation: abline(v=qnorm(c(0.025, 0.975), mean=0.1487603, sd=0.0322173), col=2) text(0.5, 10, "95% Interval with normal approx", col=2) # and with the binobp-approach: abline(v=c(0.0913896, 0.2171069), col=3) text(0.45, 8, "95% Interval with binobp", col=3) # Ergebnistabelle abspeichern (Datei wird im Working Directory angelegt), getwd() # zeigt dieses an sink(file="bayes-output.txt", append=T , split=T) # append=T: outputs werden nicht überschrieben, sondern angehängt # split=T : output wird auch in der console noch angezeigt # Benutzung eines anderen Priors: Betrachte Mittelwert und Varianz. binobp(17, 116, a = 1, b = 4) binobp(17, 116, a = 0.5, b = 1) binobp(17, 116, a = 1, b = 0.5) binobp(17, 116, a = 1, b = 1) binobp(17, 116, a = 2, b = 1) binobp(17, 116, a = 3, b = 2) # Beispiel für weitere Daten binobp(10, 174, a=1, b=4) # Schreiben in Datei beenden sink() # Posterior distribution g(pi|y) mit beta(1,lO) als prior für pi # Ziehungen = 116, Erfolge = 17, Misserfolge = 116-17 = 99 # a' = a.neu = a.alt + Zahl.Erfolge b'= b.neu = b.alt + Zahl.Misserfolge # hier: a.neu = 1 + 17 b.neu = 10 + 116 - 17 binobp(17, 116, a=1, b=10) binobp(17, 116, a=18, b=109) # posterior-beta-Funktion beta.neu = beta(18, 109) # 95% credible interval for pi: R-Ausgabe Quantile 0.025, 0.975, oder qbeta(c(0.025, 0.975), 18, 109) # Vergleich mit Normalverteilung mit gleichem Mittelwert / Standardabweichung qnorm(c(0.025, 0.975), mean= 0.1440329, sd= 0.0224784) lines(0:100/100, dnorm(0:100/100, mean=0.1440329, sd=0.0224784), col=3, lty=2) # 8.5 Hypothesentests ---------------------------------------------------------- # H0: pi = .l0 H1: pi != .10 Level of significance: 5% # Nullhypothesen-Wert pi= .10 liegt im Wahrscheinlichkeitsintervall # Nullhypothese wird nicht verworfen # H0: pi>= .15 H1: pi < .15 Level of significance: 5% # kumulierte Wahrscheinlichkeitsverteilung (pbeta) der posterior-beta-Verteilung # Gesucht ist der Wert, der in der Wahrscheinlichkeitsdichte-Verteilung der # Fläche unter der Kurve rechts des Wertes 0.15 entspricht. In der kumulierten # Wahrscheinlichkeitsverteilung bedeutet dies 1-(Wert bei 0.15) 1-pbeta(.15, shape1= 18, shape2=109) # Dieser Wert 0.37 ist größer als das Signifikanzlevel 0.05 # Die Null-Hypothese kann nicht verworfen werden -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 9: klassische Statistik ############################################ # 9.1 Hypothesentests Allgemein # 9.2.1 Tests auf Normalverteilung # 9.2.2 Transformation hin zur Normalverteilung # 9.3 Tests auf Varianzenhomogenität # 9.4 Unterschied zweier Datensätze # 9.5 Anova # 9.1 Hypothesentests Allgemein ------------------------------------------------ # P-Value: Wahrscheinlichkeit, ein Ergebnis (Datenverteilung zB) wie im Test # zu bekommen, wenn die Nullhypothese zutrifft. # Wenn p < alpha: H0 ablehnen alpha= 1-Sign.Niveau, oft 0.05 bei = 95% # alpha = Wahrsch., Fehler 1. Art zu machen (H0 ablehnen, obwohl zutreffend) browseURL("http://de.wikipedia.org/wiki/Statistische_Signifikanz") # Hypothesentest sind schwarz-weiss-Malerei, wo die Welt doch farblich (und # ultraviolett) ist, machen also nur in 0-1-Entscheidungen Sinn. # Sind immer noch kritisch zu betrachten, siehe zB: browseURL("http://www.eecs.qmul.ac.uk/~norman/blog_articles/p_values.pdf") A <- rnorm(30, mean=154) ; B <- rnorm(30, mean=392) t.test(A, B) wilcox.test(A, B) cor.test(A, B, method="p") # Überprüfung der Signifikanz der Übereinstimmung zweier Verteilungen # pairwise.wilcox.test(A, B, p.adjust.method="bonf", paired=FALSE) fakedaten <- rnorm(1000, mean=97, sd=8.9) t.test(fakedaten, mu=100, alternative="less") # p-value < 2.2e-16 < alpha # also H0 ablehnen, und davon ausgehen, dass der wahre Mittelwert aller # potentiellen Werte kleiner als 100 ist. hist(fakedaten, col=8, freq=F) lines(density(fakedaten)) # kerndichteschätzung lines(70:130, dnorm(70:130,mean=mean(fakedaten),sd=sd(fakedaten)), col=2, xpd=T) lines(70:130, dnorm(70:130,mean=97,sd=8.9), col=3, xpd=T) # 9.2.1 Tests auf Normalverteilung --------------------------------------------- browseURL("www.bb-sbl.de/tutorial/verteilungen/ueberpruefungnormalverteilung") ?binom.test ?chisq.test shapiro.test(fakedaten) ks.test(fakedaten, "pnorm", mean(fakedaten), sd(fakedaten)) # Wenn p > 0.05: Nullhypothese annehmen, daten sind normalverteilt. if(!"nortest" %in% installed.packages()[,1]) install.packages("nortest") library(nortest) # mit Lilliefors-Korrektur! help(package="nortest") ?lillie.test lillie.test(fakedaten) ad.test(fakedaten) # Anderson-Darling test for normality cvm.test(fakedaten) # Cramer-von Mises test for normality lillie.test(fakedaten) # Lilliefors (Kolmogorov-Smirnov) test for normality pearson.test(fakedaten) # Pearson chi-square test for normality sf.test(fakedaten) # Shapiro-Francia test for normality # verschiedene Möglichkeiten zur Transformation # 1/x, 1/sqrt(x), log(x), x^(1/4), x^(1/3), sqrt(x), x^2, x^3, boxcox (unten) # 9.2.2 Normalisierung mittels BoxCox-transformation --------------------------- browseURL("http://de.wikipedia.org/wiki/Box-Cox-Transformation") browseURL( "http://en.wikipedia.org/wiki/Power_transform#Box.E2.80.93Cox_transformation") # Daten generieren set.seed(42) ; Ksat <- rbeta(150, 0.3417, 1.8320)*220 # Verteilung der Daten ist nicht gaussisch: hist(Ksat, breaks=50, col=8, freq=F) x <- seq(-5, 200, len=200) lines(x, dnorm(x, mean(Ksat), sd(Ksat)), lwd=2, col=5) # doesn't fit! if(!require(car)) {install.packages("car") ; library(car) } lambda <- powerTransform(Ksat)$lambda ; lambda # 0.2254471 Ksatbc <- bcPower(Ksat, lambda) #bc: boxcox hist(Ksatbc, col=8, breaks=20, freq=F) lines(x, dnorm(x, mean(Ksatbc), sd(Ksatbc)), lwd=2, col=5) # fits much better # Alternative, hier aber gleiches Histogramm als Ergebnis library(geoR) lambdageoR <- boxcoxfit(Ksat)$lambda ; lambdageoR # 0.2254406 hist(bcPower(Ksat, lambdageoR), col=8, breaks=20, freq=F) # für Lineare Modelle siehe library(MASS) ?boxcox() # Box-Cox Transformations for Linear Models # 9.3 Tests auf Varianzenhomogenität ------------------------------------------- fligner.test( A ~ B ) # p < 0.05 impliziert: Varianzen sind unterschiedlich var.test() # anfällig gegenüber Ausreißern # install.packages("car") library(car) leveneTest() summary(aov( A ~ B)) TukeyHSD(aov(A ~ B)) kruskal.test(A, B) # 9.4 Unterschied zweier Datensätze -------------------------------------------- ?t.test # Wann welcher Signifikanztest sinnvoll ist, ist hier dargestellt: browseURL("http://de.wikibooks.org/wiki/GNU_R:_Signifikanztests") # There are two groups of values. The confidence interval overlaps, which means # that the two groups do not significantly differ. # However, the t-test returns a p-value smaller than the divide of 0.05, # indicating a significant difference of the means. # Why are the resulting interpretations contradictory? # If two confidence intervals overlap, the difference between the two means # still may be significantly different. browseURL("http://www.jstor.org/stable/view/2983411") browseURL("http://www.cmaj.ca/content/166/1/65.long") # Group 1 # Echte Daten aus einer Psychologie-Bachelorarbeit (2013) G1 <- c(92,98,102,108,99,99,88,97,114,102,114,104,101,88,102,103,102,86,85,90, 92,93,102,100,100,96,99,97,97,103,101,105,92,93,92,91,102,105,87,92,100,104,99, 93,102,94,88,94,91,100,93,83,85,90,88,93,99,100,104,102,87,92,104,106,88,98,92, 90,92,94,93,101,96,92,94,92,90,99,92,97,93,97,98,103,99,95,94,102,98,99,99,103, 107,111,106,108,104,108,97,94,92,90) # Group2 G2 <- c(115,107,111,108,102,83,94,90,102,109,106,90,113,85,109,103,102,109,94, 93,82,96,95,100,107,93,102,108,100,118,88,87,86,87,86,85,93,95,81,99,106,97,90, 93,84,83,98,119,98,100,87,80,94,90,98,99,114,103,117,123,99,106,107,126,94,91, 86,90,95,91,90,105,93,89,97,107,102,96,102,104,88,94,109,103,102,100,98,102,95, 108,92,94,95,99,102,108,97,96,107,123,83,81,89,88,114,82,96,108,109,104,93,121, 116,117,113,110,87,95,112,97,101,102,105,102,102,97,102,105,99,92,90,86,91,116, 92,93,109,107,114,108,111,105,116,114,111,96,106,104,106,101,94,100,102,97,81, 87,85,99,89,82,90,93,109,111,100,96,101,102,86,93) # the graphic with confidence intervals CI_1 <- t.test(G1)$conf.int CI_2 <- t.test(G2)$conf.int plot(1:2, 1:2, ylim=c(95,101), type="n", xaxt="n", ann=F, las=1) arrows(x0=1.4, y0=CI_1[1], y1=CI_1[2], angle=90, code=3, length=0.2) points(1.4, mean(G1), pch=16) arrows(x0=1.6, y0=CI_2[1], y1=CI_2[2], angle=90, code=3, length=0.2) points(1.6, mean(G2), pch=16) # Confidence Intervals around the mean overlap. WRONG interpretation: so the # two groups are not significantly different from each other t.test(G1, G2) # p-value = 0.0349 < 0.05 -> reject H0, accept Alternative # true difference in means is not equal to 0 -> signif. diff. of mean of groups # at conf.lev=0.95, you will WRONGLY reject H0 in 5% of (endless many) samples! # Control interpretation of p-value t.test(rnorm(100, mean=1), rnorm(100, mean=15)) # p-value < 2.2e-16 # -> difference is significant # control settings of t.test-argument var.equal var.test(G1, G2) # p-value = 4.167e-06 -> true ratio of var.s is not equal to 1 var(G1) ; var(G2) # 42 and 100 -> var.equal = FALSE is correct # Konfidenzintervälle der klasisschen (frequentistischen) Statistik sind böse: browseURL("http://www.entsophy.net/blog/?p=53") # und viele mehr! # 9.5 Anova -------------------------------------------------------------------- # ANOVA: ANalysis Of VAriances (t.test for >2 groups) # Compare the ratio of between group variance to within group variance. # If the variance caused by the interaction between the samples is much larger # when compared to the variance that appears within each group, # then it is because the means aren't the same. browseURL("http://sociology.about.com/od/Statistics/a/Analysis-of-variance.htm") browseURL("http://people.richland.edu/james/lecture/m170/ch13-1wy.html") browseURL("http://en.wikipedia.org/wiki/F_test#One-way_ANOVA_example") # AOV Beispiel nach: browseURL("http://users.minet.uni-jena.de/~jschum/biostat/ANOVA.pdf") peas <- read.table(header=T, text= "Wdh Kontr. Gluk.2 Frukt.2 Gluk.1_Sacch.2 Frukt.1 1 71 57 58 58 62 2 68 58 61 59 66 3 70 60 56 58 65 4 74 59 58 61 63 5 68 62 57 57 64 6 71 60 56 56 62 7 70 60 61 58 65 8 67 57 60 57 65 9 73 59 57 57 62 10 69 61 58 59 67") peas peas <- stack(peas[,-1]) names(peas) <- c("length", "group") head(peas, 15) summary(peas) tapply(peas$length, peas$group, mean) par(mar=c(3,6,2,1), las=1) boxplot(length~group, data=peas, col=5, horizontal=T) AOV <- aov(length ~ group, data=peas) AOV summary(AOV) par(mfrow = c(2, 2)) plot(AOV) # ANOVA Beispiel nach: browseURL("www.stat.wisc.edu/~yandell/st571/R/anova.pdf") # Daten erstellen: y1 <- c(18.2, 20.1, 17.6, 16.8, 18.8, 19.7, 19.1) y2 <- c(17.4, 18.7, 19.1, 16.4, 15.9, 18.4, 17.7) y3 <- c(15.2, 18.8, 17.7, 16.5, 15.9, 17.1, 16.7) y = c(y1, y2, y3) group <- rep(1:3, each=7) # exploratory data analysis (EDA): plot(group, y, pch=16, col=rgb(0,0,0, 0.2)) # keine überlappenden Punkte boxplot(y~group) info <- function(x) c(sum=sum(x), mean=mean(x), var=var(x), n=length(x)) info(y) tapply(X=y, INDEX=group, FUN=info) # Wende die Funktion "info" für jede "group" # getrennt auf "y" an (anwenden = apply). Siehe auch Kapitel 11.3 # Linear model and ANOVA mod <- lm(y~group) # Mehr dazu im Kapitel 14 (Regression) mod plot(y~group); abline(mod) summary(mod) str(mod) mod_aov <- anova(mod) mod_aov methods("print") ?print.anova summary(mod_aov) str(mod_aov) # tabled F values: Df <- mod_aov$Df # Degrees of freedom of treatment and error Df qf(p=c(0.05, 0.01), df1=Df[1], df2=Df[2], lower.tail=FALSE) # confidence interval on the pooled variance: SSTrt <- mod_aov["Residuals", "Sum Sq"] # SSTrt: residual sum of squares SSTrt SSTrt/qchisq(p=c(0.025, 0.975), df=Df[2], lower.tail=FALSE) # Versuch, das per Hand zu machen. Klappt noch nicht: # One-way between groups ANOVA variation != variance m1 <- mean(G1); m1 # group mean m2 <- mean(G2); m2 n1 <- length(G1); n1 n2 <- length(G2); n2 mg <- mean(c(G1,G2)); mg # overall mean (Grand mean) ssw <- var(G1)*(n1-1) + var(G2)*(n2-1); ssw # within group variation SS(W) sum((G1-m1)^2, (G2-m2)^2) # the same ssb <- n1*(m1-mg)^2 + n2*(m2-mg)^2; ssb # between group variation SS(B) (ssb/1) / (ssw/(n1+n2-2)) # stimmt so noch nicht! var.test(G1,G2)$stat -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 10: if, for (Programmieren) ######################################## # 10.1 Bedingungen (conditions): if, ifelse # Schleifen (loops): for, repeat, while # 10.2 Allgemeines zu for-Schleifen # 10.3 repeat- und while-Schleifen # 10.4 Anwendungsbeispiel # 10.5 Geschwindigkeit for-Schleifen # 10.1 Bedingungen (conditions) ------------------------------------------------ # Syntax: if(Bedingung) {Ausdruck1} else {Ausdruck2} bei 1 Wahrheitswert # Syntax: ifelse(Bedingung, Ausdruck1, Ausdruck2) für Vektor mit mehreren T/F # Wenn Bedingung wahr, dann Auswerten von Ausdruck 1, # wenn Bedingung falsch, dann Auswerten von Ausdruck 2. 7-3 > 2 # TRUE class(7-3 > 2 ) # logical, Wahrheitswert if(7-3 > 2) 18 # Bedingung ist TRUE, also gebe 18 zurück if(7-3 > 5) 18 # Bedingung ist FALSE, also passiert nichts if(7-3 > 5) 18 else 17 # Bed. F, also Rückgabe von 17 par(mfrow=c(2,1), cex=1) if(TRUE) plot(1:10) else plot(10:1) # Bedingung True, also aufsteigende Punkte # Mehrere Befehle müssen mit {} zusammengehalten werden: if(FALSE) { plot(1:10) box("figure", col=4, lwd=3) } else { plot(10:1) box("figure", col=2, lwd=3, lty=2) } # Code einrücken macht ihn menschenlesbar! # Führe den Block auch mal mit einer erfüllten Bedingung aus # Tinn R: R Send: contiguous (echo=T) # Siehe Kap. 10.1 falls .trPaths fehlt. # Unterschied zwischen "if(..) .. else .." und "ifelse(...)": # if wenn die Bedingung nur einen Wert hat # ifelse wenn ein ganzer Vektor mit Bedingungen vorliegt. bart <- c(13, 14, 15, 16, 17) bart>14 bart ifelse(bart>14, bart+1, bart-10) if(bart>14) bart+1 else bart-10 # Nimmt nur 1. Element, und warnt dabei. simpson <- -3:8 sqrt(simpson) # Warnt vor Wurzel aus negativen Zahlen sqrt(ifelse(simpson >= 0, simpson, NA)) # läuft sqrt(if(simpson >= 0) {simpson} else NA) # geht nicht, denn simpson ist Vektor. ?"if" # Zeilenumbrüche zwischen '}' und 'else' sind zu vermeiden, wenn via Editor # die Befehle Zeilenweise an R geschickt werden! ergebnis <- 1/4 # Ergebnis vorheriger Berechnungen if( ergebnis > 0.2 ) message("Ergebnis ist > 0.2 und das ist relevant.\n") # Sowas kann man gut in Funktionen einbauen! # Eine ganze Reihe von Bedingungen ist daher in Kapitel 12 verwendet. # Zur Abkürzung T und F siehe Kapitel 19.5 Logische Operatoren # Wenn Rechenzeit für dich wichtig wird: # "ifelse() is for vectorized conditions. if(){} else{} is more efficient # for length 1 conditions than ifelse()" Uwe Ligges, R-help 2004 # Schleifen (loops) ------------------------------------------------------------ # 10.2 Allgemeines zu for-Schleifen -------------------------------------------- # mehrfaches Ausführen eines Codeblocks, zB Erstellen mehrerer Bilder # Syntax: for ( EinLaufbuchstabe in EineSequenz) { machwas } # Zwischen den {} können mehrere Befehle stehen, die i-fach / für i verschiedene # Werte durchgeführt werden, auch über mehrere Zeilen getrennt. # Bei einem einzelnen Befehl können die {} weggelassen werden. help("for") for(i in c(2,5,9) ) print(1:i) # man verwendet oft i für index # im ersten Durchlauf wird an den Befehl i mit dem Wert 2 übergeben. # Der Befehl wird ausgeführt, dann fängt die Schleife von vorne an und führt # den Code mit dem nächsten Wert aus. # mit for einen Vektor füllen v <- vector("numeric", 20) v for(i in 3:17) v[i]= (i-2)^2 # für jedes i wird der Code einmal ausgeführt v # Ist in R sehr langsam - vektorisieren ist 100 fach schneller. -> 10.2.4 # Erstellen mehrerer Graphiken. Besonders sinnvoll in Kombination mit anderen # Devices, zB png, bmp oder pdf (Siehe Kap 4.10) windows(record=T) # Aufzeichnung der Einzelbilder starten plot(1, ylim=c(0,7)) plot(3, ylim=c(0,7)) for (i in 1:7) plot(i, ylim=c(0,7)) # mit Bild Up, Bild Dn durchklicken # Addieren mehrerer Linien zum Plot z3 <- seq(0,25,0.1) plot(z3,z3, type="n") lines(z3, 12.5*5/factorial(4)*(z3/8*5)^(4)*exp(-z3/8*5), col=2 ) lines(z3, 12.5*6/factorial(5)*(z3/8*6)^(5)*exp(-z3/8*6), col=2 ) for (n in 7:25) lines(z3, 12.5*n/factorial(n-1)*(z3/8*n)^(n-1)*exp(-z3/8*n), col=2 ) # Laufende Dateinamen oder Objektnamen erstellen: getwd() # mit setwd auf einen Ordner mit Schreibberechtigung setzen # Ja, beschränkte Rechte auf C:\ sind für viele (unerfahrene) Nutzer sinnvoll! meinevar <- c(12,14,15,28,76) for(k in 1:4) { out <- rexp(k) write.table(out, paste("MeinName", meinevar[k], ".txt", sep="") , quote=F)} cat("Hier sind deine Textdateien:\n", getwd(), "\n") # \n newline, Kap 17.1 # Jetzt Dateien wieder löschen unlink(paste("MeinName", meinevar[1:4], ".txt", sep="") ) # riskanter Befehl! # Das Skript kann sich zB selbst löschen, wenn man den ganzen Ordner löscht! # 10.3 repeat- und while-Schleifen --------------------------------------------- # Wiederholung von Befehlsaufrufen, Iterationen, Simulationen # Syntax: repeat {Ausdruck} # Wiederholung des Ausdrucks # next # Sprung zum nächsten Iterationsschritt # break # Verlassen der Schleife # Syntax: while(Bedingung){Ausdruck} # Wiederholung, solange Bed. erfüllt i <- 0 # Lege Objekt i mit dem Wert 0 an repeat # wiederhole nachfolgenden Codeblock immer wieder { # Codeblock beginnt i <- i + 1 # überschreibe Objekt i mit neuer Zahl if (i < 3) print(i) # wenn i kleiner ist als 3, dann Ausgabe in der Konsole if (i == 3) break # wenn i gleich 3 ist, wird die Schleife abgebrochen. } # Codeblock endet i # beim letzten Durchlauf wurde 1 zu 2 hinzugefügt (=3), und das als i angelegt i <- 0 while(i < 3) i <- i + 1 # Während (while) 1<3 ist, wird Code ausgeführt i # Werden beides in der Umwelt-Datenanalyse sehr selten angewendet, repeat habe # ich sogar noch nie in der Realität gebraucht. # 10.4 Anwendungsbeispiel ------------------------------------------------------ # Punkte zufällig festlegen, aber mit Mindestdistanz zueinander. set.seed(42) # Startpunkt für den Zufallszahlengenerator festlegen. So hast du # die gleichen Ergebnisse wie ich. # Zielvektor für 20 zufällig verteilte Punkte erstellen: x <- rep(NA, 20) # Ersten Wert reinschreiben: x[1] <- runif(1, 10, 80) # Zufallszahlen gleichmäßig zwischen 10 und 80 verteilt x count <- 1 # Anzahl Versuche, die benötigt werden # 19 Punkte hinzufügen for(i in 2:20) # Code zur Übersichtlichkeit einrücken! { x[i] <- runif(1, 10, 80) # random aus uniform-verteilung count <- count+1 # Wenn eine minimale Distanz von 1.7 zu den anderen Punkten nicht gegeben # ist, wird der Punkt ersetzt, also nochmal zufällig gezogen while( min( abs(x[i] - x[-i]), na.rm=T ) < 1.7 ) { x[i] <- runif(1, 10, 80) count <- count+1 } # Ende while-Schleife | schreibe ich bei mehreren } oft dazu, damit } # Ende for-Schleife | ich schnell sehen kann, wozu es gehört. x count # 45 versuche, 20 Punkte zwischen 10 und 80 mit dist > 1.7 zu verteilen. plot(x, rep(1,20)) # Jetzt sind die Punkte zufällig gesetzt, aber immer mit einer minimalen Distanz # zueinander. Dies ist für Versuchsplanungen (sampling design) interessant. # Um Methoden der statistischen Inferenz (Schluss von einer Stichprobe auf die # Grundgesamtheit) anwenden zu können, müssen die Stichpr. zufällig gezogen sein points(runif(80, 10, 80), rep(c(0.6, 0.8, 1.2, 1.4),each=20), col=2, pch=17) # Liegen mitunter sehr geklumpt und decken weniger gut den ganzen Bereich ab. # 10.5 Geschwindigkeit for-Schleifen ------------------------------------------- # Generell sind Schleifen in R in der Berechnung um ein Vielfaches langsamer als # vektorisierte Rechnungen. Bei größeren Datensätzen (> 500 Zeilen zB) solltest # du sie nach Möglichkeit vermeiden und lieber apply (Abschnitt 10.3) verwenden. # Sind sie trotzdem nötig, macht es immer Sinn, erst den gesamten Vektor mit # NA oder 0 Werten zu erstellen, und diese dann einzeln zu füllen. Denn sonst, # wenn ein leerer Vektor mit sovielen Elementen gefüllt wird, muss er nach jedem # Schleifendurchlauf neu gespeichert werden --> "cannot allocate"-Fehler. # Beweis: Vektorisieren ist besser! x <- rnorm(5e6) # 5 Mio Zufallszahlen aus der Standardnormalverteilung system.time( for (i in seq(along=x)) x[i] <- x[i]^2 ) # 11.42 Sekunden bei mir system.time( x <- x^2 ) # vektorisierte Alternative # 0.03 Sekunden! # Beweis: Vektor mit richtiger Länge vorbereiten ist besser! x <- rnorm(1e5) y <- numeric() # Leerer Vektor der Länge Null system.time( for (i in seq(along=x)) y[i] <- x[i]^2 ) # 12.58 Sek y <- numeric(1e5) # Leerer Vektor mit 0.1 Mio Elementen system.time( for (i in seq(along=x)) y[i] <- x[i]^2 ) # 0.22 Sek system.time( y <- x^2 ) # 0 Sek # Merke: Schleifen sind langsam in R! (in z.B. FORTRAN oder C nicht) # - Vermeide lange Schleifen durch Vektorisierung # - für Informatiker und Nerds: Code-Auslagerung "Calling C and Fortran from R": browseURL("http://cran.r-project.org/package=Rcpp") browseURL("http://users.stat.umn.edu/~geyer/rc/") # - Oder lerne, apply Funktionen anzuwenden. Die sind schnell und oft ganz toll, # aber leider für Anfänger nicht immer leicht zu lernen. # Da sich das aber wirklicht lohnt, soll das nächste Kapitel (11) dabei helfen. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 11: apply-Funktionen ############################################### # Motiviert durch niedrige Geschwindigkeit for-Schleifen (Kapitel 10.5) # apply und Co sind außerdem eleganter! # 11.1 die Anwende(apply)-Funktionen in Übersicht # 11.2 apply: "anwenden" # 11.3 tapply: tagged-apply (pr Kategorie) # 11.4 lapply: list-apply und sapply: simplify-apply # 11.5 mapply: multiple-apply # 11.6 Rechenzeit for, lapply, apply # 11.7 Parallel Computing unter Windows # 11.8 Übungsaufgabe # 11.1 die Anwende(apply)-Funktionen in Übersicht ---Argumente---------------- ?apply # Spalten- oder zeilenweise Funktion ausführen X, MARGIN, FUN ?tapply; ?by # table/tag-apply in Gruppen (Tags) X, INDEX, FUN, simplify ?aggregate # tapply für data.frames statt nur Vektoren x, by, FUN, simplify ?lapply # list-apply X, FUN ?sapply # simplify-apply, sonst wie lapply X, FUN, simplify ?mapply # multiple-apply FUN, MoreArgs, SIMPLIFY # Leider sind die Argumente recht unterschiedlich benannt und geschrieben... # Daher lasse ich sie oft unbenannt. In der Default-reihenfolge geht das ja. # Eine sehr stark verkürzte Variante dieses Kapitels (auf englisch): browseURL("http://stackoverflow.com/a/7141669/181638") # Auch diese Seite finde ich ziemlich gut: browseURL( "http://nsaunders.wordpress.com/2010/08/20/a-brief-introduction-to-apply-in-r") # 11.2 apply: "anwenden" ----------------------------------------------------- m <- matrix(sample(1:100, 24), ncol=6) rownames(m) <- letters[1:4] ; colnames(m) <- LETTERS[21:26] m apply(X=m, MARGIN=2, FUN=mean) # mean spaltenweise (MARGIN=2) anwenden apply(X=m, MARGIN=1, FUN=max) # max zeilenweise (MARGIN=1) anwenden --> vector apply(X=m, MARGIN=1, FUN=range) # --> matrix colMeans(m) # für einfache Funktionen gibt's die auch direkt rowSums(m) # Übung: Erstelle eine Tabelle mit mu und sd von m, mit Zeilen- und Spaltennamen # Anwendungsbeispiel apply: Array # Wirtschaftsdaten mehrerer Länder, Jahre, und Sektoren load("Daten/11_econ.Rdata") # fiktive Daten aus Dominik Reusser's R-Kurs 2011 # falls bisher nicht runtergeladen: load(url("http://dl.dropbox.com/u/4836866/Rclick/Daten/11_econ.Rdata")) # Siehe Kap. 10.3 ls() econ str(econ) class(econ) # array, also matrix mit (hier) 3 Dimensionen - gut für regelmäßige mode(econ) # numeric, also alles mit Zahlen Zeitreihen geeignet # Indizierung von Arrays dimnames(econ) econ["DE", ,] # Daten von Deutschland anzeigen econ[,"Industrie",] # Industrie-Daten econ[,,"2003"] # Daten aus 2003, Analog: econ[,,2] # zweites Element der dritten Dimension (hier: "2002") # Mittelwerte über Länder, Jahre, und Sektoren # Das MARGIN-Argument gibt an, welche Dimension behalten wird: apply(econ, MARGIN=c(1, 2), FUN=mean) apply(econ, 2:3, mean) # bei Angabe in richtiger Reihenfolge können apply(econ, 1, mean) # Argumentnamen weggelassen werden apply(econ, 2, mean) apply(econ, 3, mean) apply(econ, 3, quantile) # Siehe auch: browseURL("http://de.wikibooks.org/wiki/GNU_R:_apply") # 11.3 tapply: tagged-apply --------------------------------------------------- data() # Zur Verfügung stehende Datensätze head(chickwts, 15) # Hühnerwachstum abhängig von Fütterungstyp tapply(X=chickwts$weight, INDEX=chickwts$feed, FUN=mean) # Der Datensatz X wird anhand des INDEX gruppiert, bevor auf jede Gruppe die # Funktion FUN angewendet wird. Die Ausgabe ist vom Typ array, mit Namen. # t-apply steht ggf für tagged apply (the tags identify the subsets) sort(tapply(chickwts$weight, chickwts$feed, mean)) # Für histogramme pro Gruppe siehe # 11.5 mapply # Übung: schaue via tapply nicht nur mean, sondern auch min und max an # Eine Funktion, die je zwei Werte zurück gibt, wird als array ausgegeben: tapply(chickwts$weight, chickwts$feed, range) futtergew <- tapply(chickwts$weight, chickwts$feed, range) View(futtergew) # Objekts wird dabei intern in ein data.frame umgewandelt sapply(futtergew, I) # macht ein echtes Dataframe draus # sapply ist in 11.4 und 11.5 erklärt und wendet hier die Funktion I auf # jedes Element der Liste an. I gibt im Wesentlichen den jeweiligen Input ohne # Attribute zurück. class(tapply(chickwts$weight, chickwts$feed, mean)) class(tapply(chickwts$weight, chickwts$feed, range)) # Anwendungsbeispiel tapply: iris-Daten head(iris) # Größen von Kelch- und Kronenblätter dreier Schwertlilienarten ?iris str(iris) tapply(X=iris$Petal.Length, INDEX=iris$Species, FUN=mean) tapply(iris$Petal.Length, iris$Species, max) summary(iris) tapply(iris$Petal.Length, iris$Species, summary) # Für Tabellen verwendet man "by", annstatt INDEX heißt das Argument da INDICES by(iris[,1:4], INDICES=iris$Species, FUN=sum) # mit mean funktioniert das nicht so wie bei Neil Saunders. # ToDo: rausfinden, warum nicht. # Für ganze Datensätze aggregate verwenden (tapply nimmt als X nur einen Vektor) state.x77 # Info über USA-Staaten state.region # Regionen der Staaten der USA cbind(state.x77, state.region) # schön sichtbar, dass die Regionen factors sind, # die intern mit ganzen Zahlen beschrieben werden aggregate(state.x77, by=list(Region = state.region), FUN=mean) # Datensätze nach Kriterium auftrennen: tapply(chickwts$weight, chickwts$feed, function(x) x) # Funktion gibt input # geht eleganter mit # unverändert zurück tapply(chickwts$weight, chickwts$feed, I) # und noch eleganter mit split(chickwts$weight, chickwts$feed) # Anwendungsbeispiel tapply: Gruppierung nach mehreren Faktoren head(warpbreaks) str(warpbreaks) # mittlere Anzahl Garn-Brüche (X) beim Weben nach Fadenspannung (INDEX): tapply(X=warpbreaks$breaks, INDEX=warpbreaks$tension, mean) # mittlere Anzahl Brüche nach Wolle-typ: tapply(warpbreaks$breaks, warpbreaks$wool, mean) # mittlere Anzahl Brüche nach Spannung und Wolle-typ: tapply(warpbreaks$breaks, warpbreaks[,2:3], mean) # Anwendungsbeispiel tapply: "gleitendes Mittel" (moving average) # 10'000 äquidistante Daten. Mittelwert alle 100 Punkte. x <- cumsum(rnorm(10000)) # hypothetische Daten plot(x, type="l", col=8) mx <- tapply(x, rep(1:100, each=100), mean) lines(seq(0,10000, leng=100), mx, col=2, lwd=2) wid <- 100 # Breite des gleitenden Fensters fexibler tapply(x, rep(1:(length(x)/wid), each=wid), mean) # Andere Lösung: rowMeans(matrix(x, ncol=100, byrow=TRUE)) # Ich bin zoo-Gegner, ich sehe den Nutzen nicht. Überzeuge mich doch 🙂 install.packages("zoo") require(zoo) ?rollapply # from package zoo z2 <- zoo(round(rnorm(15),1)); z2 rollapply(z2, 3, mean, by = 3) # means of nonoverlapping groups of 3 # PS: ein echtes gleitendes Fenster hätte Überlappungen # Hab deswegen eine rollapply Äquivalente für normale Daten in Kap 12 (movAv) # 11.4 lapply: list-apply und sapply: simplify-apply --------------------- bart <- list(1:10, 2:30, 3:40) bart lapply(bart, mean) # list sapply(bart, mean) # vector (s für simplify list to vector) # lapply statt for-Schleifen: Spalten gegeneinander plotten dat.a <- as.data.frame(matrix(runif(20),ncol=4)) dat.a dat.b <- as.data.frame(matrix(runif(20),ncol=4)) par(mfrow=c(2,2)) for(i in 1:4) plot(dat.a[,i], dat.b[,i], pch=16, main=i) # lange for-Schleifen ersetzen mit lapply (rechnet um ein vielfaches schneller): dummy <- lapply(1:4, function(i){plot(dat.a[,i], dat.b[,i], pch=16, main=i)} ) dummy # Hier nicht benötigter Kram, daher auch dummy genannt graphics.off() # Rechenzeit: dat <- matrix(rnorm(5e6), ncol=50) dim(dat) # 100'000 Zeilen, 50 Spalten Erg <- NA # Vektor mit Ergebnis je Zeile: Wert genau zwischen min und max system.time( for(i in 1:100000) Erg[i] <- mean(range(dat[i,])) ) rm(Erg) # 53 Sekunden (Es lebe SSD! Bei alten PCs mehr) system.time( Erg <- sapply(1:1e5, function(i) mean(range(dat[i,])) ) ) # 3.7 Sekunden = 7% der Rechenzeit der Schleife !! hist(Erg) # Man kann also (nichtrekursive) Schleifen ganz einfach schneller machen: # Einfach "sapply(1:n, function(i)" und ")" drumherum schreiben. # Und man muss vorher keine leeren Objekte erstellen. Erg <- rep(NA, 100000) # auch 3.7 Sekunden system.time( for(i in 1:100000) Erg[i] <- mean(range(dat[i,])) ) # weiteres Beispiel - lapply und sapply im Vergleich: x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE)) x dim(x); class(x) # list mit 3 elementen length(x) # jedes dieser Bestandteile hat selbst wieder eigene Elemente lapply(x, mean) sapply(x, mean) # simplify list to vector # Anwendungsbeispiel sapply: Quantile set.seed(2) # legt einen Startpunkt für den Zufallszahlengenerator fest, dadurch # sind die reproduzierbar: du kriegst die gleichen "Zufalls"zahlen wie ich. Ksat <- round(rexp(n=45, rate=0.02),1) # Random EXPonentially distributed quantile(Ksat) # 25% der Daten ist kleiner als 16.3 # 100%-75% = 25% der Daten ist größer als 73.7 (75% Quantil) # 9-Zahlenmaß: Median, Quartile (Fourth), Oktile (Eighth), Hexadezile, Range # Quantile kann verschiedene Algorithmen für die Berechnung verwenden (type) # Um das schneller zu vergleichen, schreiben wir eine Funktion: myquant <- function(tp) quantile(Ksat,prob=c(0,1,2,4,8,12,14,15,16)/16, type=tp) # Die führt dann jeweils abhängig von tp quantile von Ksat aus myquant(tp=1) # Mehr zu Fuktionen in Kap 12. Wenn du nachvollziehen kannst, myquant(3) # was hier passiert, reicht das aber erstmal. # insbesondere bei den hohen Quantilen ist das Ergebnis abhängig vom type! # (weil dort in diesem Datensatz weniger Werte sind) # Vergleich in einer Tabelle: quants <- sapply(X=1:9, FUN=myquant); quants # simplify-apply # deutlich eleganter (und schneller) als mit einer for-Schleife. boxplot(t(quants), at=c(0:2,4,8,12,14:16)/16, boxwex=0.1, xlim=0:1, las=1, horizontal=TRUE) # Methoden unterscheiden sich stark wenn wenig Werte da sind... lines(ecdf(Ksat), verticals=T, do.points=F, col=2, lwd=3) # Anderes Beispiel für Ökonomen: # Fake Data: Einkommen von Leuten in verschiedenen Einkommensklassen set.seed(42) # Startpunkt für Zufallszahlengenerator (zur Reproduzierbarkeit) Einkommen <- round(c(rexp(20)*1e4, rexp(20)*1e5, rexp(20)*1e6)) Klasse <- rep(c("1.low", "2.mid", "3.high"), each=20) # Funktion definieren, die die benötigten Kennwerte rausgibt: dezile <- function(input) quantile(input, probs=c(0.1, 0.9) ) dezile(Einkommen) # funktioniert schonmal # Jetzt nach Klassen getrennt: tapply(Einkommen, INDEX=Klasse, FUN=dezile) # list Ausgabe unübersichtlich sapply(X=tapply(Einkommen, INDEX=Klasse, FUN=dezile), FUN=I) # lapply kann eine "list" zu einem "data.frame" umwandeln, siehe l2df im # Paket BerryFunctions install.packages("berryFunctions"); library("berryFunctions") ?l2df # Ähnlich wie lapply funktioniert auch do.call: eg3 <- list(KA=data.frame(SW=1:6, SB=2:-3), LS=data.frame(SW=23:24, SB=c(-3,2))) eg3 do.call(rbind, eg3) # 11.5 mapply: multiple-apply ------------------------------------------------ check.math <- function(a,b,c) cat(paste(a,"+",b,"=",c, ifelse(a+b==c,"ist richtig","ist falsch"),"\n")) check.math(3,4,7) check.math(4,5,7) alang <- c(6,2,4,5) blang <- c(5,3,5,9) clang <- c(3,5,8,7) dummy <- mapply(check.math, alang, blang, clang) # Histogramme einzelner Gruppen mit Überschrift par(mfrow=c(2,3)) mapply(hist, split(chickwts$weight, chickwts$feed), main=levels(chickwts$feed), MoreArgs=list(xlim=range(chickwts$weight), col=2, breaks=1:10*50)) # Für ProgressBars in *apply-Funktionen siehe: #browseURL(paste("http://ryouready.wordpress.com/2010/01/11/", # "progress-bars-in-r-part-ii-a-wrapper-for-apply-functions", sep="")) install.packages("pbapply") library("pbapply") dummy <- pbsapply(rep(0.02, 100), Sys.sleep) # 11.6 Rechenzeit for, lapply, apply ------------------------------------------- n <- 1e3 dat <- matrix(rnorm(n*50), ncol=50) library("microbenchmark") mr_bad_for <- function() {Result <- NA for(i in 1:n) Result[i] <- mean(range(dat[i,])) ; Result} mr_good_for <- function() {Result <- rep(NA, n) for(i in 1:n) Result[i] <- mean(range(dat[i,])) ; Result} mr_sapply <- function() {Result <- sapply(1:n, function(i) mean(range(dat[i,])) ); Result} mr_apply <- function() {Result <- apply(dat, MARGIN=1, function(x) mean(range(x))); Result} system.time(mr_good_for()) system.time(mr_good_for()) # will be slightly different each time # Folgende Berechnung dauert relativ lange! - n ggf. runtersetzen speed <- microbenchmark(mr_bad_for(), mr_good_for(), mr_sapply(), mr_apply(), times=20) speed plot(speed) # if there is one extreme outlier, run it again par(mar=c(3,7,2,1)) plot(speed, horizontal=TRUE, las=1) library("ggplot2") autoplot(speed) # microbenchmark for other tasks: library("microbenchmark") a <- sample(0:1, size=3e6, replace=TRUE) speed <- microbenchmark(a != 0, ! a == 0, times=50) boxplot(speed, notch=TRUE, unit="ms", log=F) # 11.7 Parallel Computing unter Windows ---------------------------------------- # Motivation: kürzere Rechenzeit ein Literaturbeispiel von Tausenden: browseURL("www.fernuni-hagen.de/FACHSCHINF/1727/Zusammenfassung.pdf") # Für UNIX-Systeme gibt es die Pakete parallel und multicore - Für Windows snow if(!require(snow)) {install.packages("snow") ; require(snow) } cl <- makeCluster(4) # 4 Kerne auf dem Rechner # Ggf. vorher notwendig: Objekte an Cluster übergeben: clusterExport(cl, c("centroide","patchsize","distance")) browseURL("http://stackoverflow.com/questions/10095956") # Nimm eine kleinere Zahl, falls der PC für dieses Beispiel zu langsam ist: sinnlos <- function(i) quantile(rnorm(1e8)) system.time( sinnlos(1) ) # 12 sek system.time( sapply(1:10, sinnlos) ) # 131 sek system.time(parSapply(cl, 1:10, sinnlos) ) # 42 sek # Nie vergessen: stopCluster(cl) # Noch mehr RAM usage leeren: gc() # Das sind die Speicherfresser sort(sapply(ls(), function(x) object.size(get(x)))/1e6, dec=T) # in MB # 11.8 Übungsaufgabe ----------------------------------------------------------- # Gegeben sind folgende (fiktive) Daten aus unregelmäßigen Messkampagnen: UebDat <- read.table("Daten/11_applytest.txt", header=T) # oder File <- "http://dl.dropbox.com/u/4836866/Rclick/Daten/11_applytest.txt" UebDat <- read.table(url(File), header=T) UebDat # Diese Zeitreihen sollen so als Boxplots dargestellt werden, dass das Skript # auch mit weiteren Daten laufen wird. Nutzungstypen sind zu berücksichtigen. # Zudem will man für jede Nutzung und jedes Jahr den Mittelwert mit einzeichen. # Eine mögliche Lösung findet sich weiter unten, aber probiere doch erst selbst. # Bessere oder elegantere Lösungen sind - wie immer - willkommen! View(UebDat) # Parameter fürs Plotten ermitteln Jahre <- min(UebDat$Jahr):max(UebDat$Jahr) nJ <- length(Jahre) # Anzahl Jahre Range <- range(UebDat$Wert) # Wertebereich Range[2] <- Range[2] + 0.05*diff(Range) # zweiter Wert höher für Anzahlangabe # Daten nach Landnutzung auftrennen Dat <- split(UebDat, UebDat$Nutzung) class(Dat) str(Dat) nN <- length(Dat); nN # 2, number of Nutzungen # Nutzungen je in einem eigenem Fenster darstellen par(mfrow=c(nN,1), mar=c(2,3,1,1), mgp=c(3,0.5,0)) for(i in 1:nN) { # evtl NAs in fehlenden Jahren hinzufügen -> Bereich auf allen Achsen gleich fehl <- Jahre[!Jahre %in% Dat[[i]][,"Jahr"]] toplot <- Dat[[i]][2:3] if(length(fehl)>0) toplot<-rbind(Dat[[i]][2:3], data.frame(Jahr=fehl,Wert=NA)) # Das eigentliche Plotten posit <- boxplot(tapply(toplot[,2], toplot[,1], function(input) input), ylim=Range, main=names(Dat)[i], las=1, col=sample(colors(), nJ)) points(1:nJ, tapply(toplot[,"Wert"], toplot[,"Jahr"], mean), pch=8) text(1:nJ, posit$stats[5,], paste("n =", posit$n), adj=c(0.5,-0.2)) rm(fehl, toplot, posit, i) }# Ende for-Schleife # Das alles ist jetzt unproblematisch nochmal für folgende Daten möglich: set.seed(8) UebDat <- data.frame(Nutzung=sample(c("Wald","Wiese","Acker"), 90, rep=T), Jahr=sample(2005:2013, 90, rep=T), Wert=sample(100:300, 90, rep=T) ) # entsprechende Zeilen oben nochmal abschicken... -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 12: Funktionen ##################################################### # 12.1 Funktionseinführung # 12.2 Einfache Beispiele # 12.3 Verweis auf Paket berryFunctions # 12.4 Weitere mögliche Argumente # 12.5 Lexical scoping - wo kommen die Variablen her? # 12.6 Input prüfen ist wichtig (Exception handling) # 12.7 Beispiele für praktische Funktionen # 12.7.1 Rechteck manuell in Graphik zeichnen # 12.7.2 Gleitendes Mittel # 12.7.3 Fonttester # 12.7.4 SCS Verfahren zur Bestimmung des Abfussbeiwertes # 12.1 Funktionseinführung ----------------------------------------------------- # Funktionen schreibt man oft, wenn man Code mehrfach ausführen muss/will, oder # wenn man Routinen für andere Leute schreiben will. # Generelle Struktur: Funktionsobjektname <- function(argument1, argument2, ...) {"Rechenanweisungen"} ?"function" # 12.2 Einfache Beispiele ------------------------------------------------------ # Daten sollen geplottet und mit 7 multipliziert zurückgegeben werden: myfunct <- function(grappig) { plot(grappig, type="l") return(grappig*7) } # grappig ist Niederländisch und symbolisiert die freie Benennung der Argumente. myfunct( c(5,11,3,7) ) # return() # gibt das was drin steht zurück, und danach wird die Funktion # nicht weiter ausgeführt! Sollte also erst am Ende stehen. # Es muss nicht gesetzt werden: die letze Anweisung ("expression") wird auch # ohne return zurück gegeben: myfunct <- function(grappig) {plot(grappig, type="l"); grappig*7 } myfunct( c(5,11,3,7) ) # Nullstellen (P-Q-Formel) linearer Funktionen y = x^2 + px + q pq <- function(p,q) { w <- sqrt( p^2 / 4 - q ) c(-p/2-w, -p/2+w) } # Ende der Funktion # Code einrücken erhöht die Menschenlesbarkeit enorm! # Funktion verwenden pq(3, -12) # -5.274917 2.274917 # Gleich mit Plotten im angegebenen Bereich pq <- function(p,q,a=-5, b=5) # Standardwerte mit "=" vorgeben (defaults) {x <- seq(a, b, len=100) plot(x, x^2+p*x+q, type="l"); abline(h=0, v=0) w <- sqrt( p^2 / 4 - q ) c(-p/2-w, -p/2+w) } pq(3, -12) # a und b haben bereits Standardwerte, müssen nicht angegeben sein. pq(3, -8, a=-7) # können aber (auch einzeln) geändert werden pq(3, -8, , 3) # Nicht namentlich genannte Argumente müssen in der richtigen Reihenfolge sein, # bei Änderung der Reihenfolge muss man sie aber angeben: pq( a=-2, q=-12, p=3) # Funktionen werden zudem oft in Solvern benötigt, zB um ein Minimum finden: optimize( f=function(x) x^2 + 3*x - 12 , interval=c(-5, 5) ) # Siehe Kapitel 18: Optimierung # Wurzel aus Skalarprodukt zweier Vektoren ?"%*%" wsk <- function(x, y) drop( sqrt(x%*%y) ) # drop macht aus matrix ein vector wsk(1:4, 4:1) wsk(c(5.2,pi,-3), c(7,-4,7.5)) # Barcodes erstellen barcode <- function() { # einfache Verwendung von function: Code zusammenfassen par(mar=c(0,0,0,0)); layout(matrix(1,1,1), widths=lcm(15), heights=lcm(9)) t4 <- data.frame(a=1:500, b=ifelse(rnorm(500)>0.9, 1, 0)) plot(t4, type="n", xaxt="n", yaxt="n" ) abline(v=t4[t4$b==1,1], lwd=3); box(col="white") } windows(record=T) for (i in 1:20) barcode() # mit PG up/dn (Bild) kann man die Bilder durchklicken # Erste und letze Zeilen einer Tabelle flast <- function(dat, n=3) return(dat[c(1:n,(nrow(dat)-n+1):nrow(dat)),]) flast( data.frame(letters, rt(26, 5)) ) # eleganter mit: head, tail flast <- function(dat, n=3) rbind( head(dat, n), tail( dat, n) ) flast( data.frame(letters, rt(26, 5)) ) # Interferenz durch Pixelabstände x <- seq(-pi,pi,len=1000) par(mar=rep(0,4)) coola <- function (a) plot(a*sin(x), a*cos(x), asp=1, type="l") coolb <- function (a) lines(a*sin(x), a*cos(x)) coola(10) for(i in 5:99/10) coolb(i) # Zieh mal die Graphik kleiner und größer... # In einer Funktion auf Objekte zugreifen: get() obj_1 <- cumsum(rnorm(1000)) obj_2 <- cumsum(1:10*c(-2,3)) testf <- function(k) plot( get(paste0("obj_", k)), type="l" ) testf(1) testf(2) # Integrale f <- function(x) {-x*x +7} plot(-10:40/10, f(-10:40/10), type="l") abline(v=0, h=0) f(1) integrate(f, 0, 1.5) lines(c(1.5,1.5,0,0:15/10), c(f(1.5),0,0,f(0:15/10)), col=2, lwd=2) text(.75, 3, 9.4, col=2) # 12.3 Verweis auf Paket berryFunctions ---------------------------------------- browseURL("http://cran.r-project.org/web/packages/berryFunctions/index.html") # Dieses Paket hat unter anderem auch eine Menge meiner Helper-Functions install.packages("berryFunctions") library(berryFunctions) ?berryFunctions # Feedback ist herzlich willkommen! # 12.4 Weitere mögliche Argumente -------------------------------------------- testdots <- function(x,...) plot(x, ...) # dots expansion, three dots, ellipsis testdots(3:8) testdots(3:8, main="zwo") # oder was auch immer. # to pass ... to a different function: myfunc <- function(g, ...) {plot(g); list(...)} myfunc(8, buh=6) # Für jede Funktion eine eigene Argumentliste: tp <- function(...) {plot(7:8, ...) ; legend("top", "Text hier", ...)} tp() tp(type="o") # legend hat kein type! die Lösung: berryFunctions::owa # different Ellipsis passed to different functions, each with their own defaults ?owa # argument overwriting and combining. Read the examples. # 12.5 Lexical scoping - wo kommen die Variablen her? -------------------------- x <- 2 ls() # x ist ein Objekt (Variable) im Global Environment, dem user workspace f <- function(y) c(x,y) f(7) # x wird aus dem globalenv() gezogen, es gibt kein x innerhalb der Funktion f <- function(y) {x <- 3; print(environment()); c(x,y)} f(7) # hier kommt x aus dem funktionseigenen temporären environment x # im globalenv hat x nach wie vor die Zahl 2 # Das ist bei geschachtelten Funktionen komplizierter. Für Fortgeschrittene: browseURL("http://andrewgelman.com/2014/01/29/stupid-r-tricks-random-scope/") # Für Anfänger eher geeignet, mit Übungsaufgaben: browseURL("http://adv-r.had.co.nz/Functions.html") tf <- function(x) {if(x)buh=8; list(exists("buh", inherits=FALSE), buh)} tf(T) tf(F) # geht nicht, buh existiert nicht buh=7 tf(T) tf(F) # buh existiert nicht im Function environment, aber in globalenv() # Nur einmal pro Sitzung warnen/informieren # r.789695.n4.nabble.com/Display-warning-only-once-in-session-td4696005 myFunc <- local({ # (c): Bill Dunlap, TIBCO Software notWarnedYet <- TRUE function(x) { if (notWarnedYet) { warning("myFunc is funky") notWarnedYet <<- FALSE # note use of <<- } sqrt(log2(x)) } }) myFunc(1:5) myFunc(1:5) myFunc(1:5) # 12.6 Input prüfen ist wichtig (Exception handling) --------------------------- # z.B. sollen in folgender Berechnung der Fläche eines planaren Dreiecks # 3-stellige Vektoren mit je den x und den y-Koordinaten der Ecken eingehen. # Bei anderen Eingaben soll mit Fehlermeldung abgebrochen werden. dreieck <- function(x, y, digits=3) { if( !is.vector(x) | !is.vector(y) ) stop("Input müssen Vektoren sein!") if(length(x) != 3 | length(y) !=3 ) stop("Vektoren sind nicht 3-stellig") A <- 0.5*(x[1] * (y[2]-y[3]) + x[2] * (y[3]-y[1]) + x[3] * (y[1]-y[2])) return(round(abs(A),digits)) } a <- c(1,5.387965,9); b <- c(1,1,5) plot(a[c(1:3,1)], b[c(1:3,1)], type="l", asp=1)#; grid() dreieck(a,b) dreieck(a,b[1:2]) # Always try to make your functions foolproof. That way, if someone else uses it # wrongly, they'll know what they did wrong. And by the way, this includes you # yourself, three years later. (or 3 weeks, actually) # cycle a vector, eg change 1 2 3 4 5 6 7 to 4 5 6 7 1 2 3 Cycle <- function(vector, shift) { # make nice indents to keep things readable # make sure only vectors are supplied as input if(!is.vector(vector)) stop("input has to be a vector") # don't mess with shift: It has to be ONE integer, less than vectorlength if(length(shift) > 1) stop("shift should be ONE number") if(is.na(as.integer(shift))) stop("shift has to be an integer") n <- length(vector) if(shift >= n) stop("shift has to be smaller than length(vector)") # Well, here's the actual thing happening: vector[c((shift+1):n, 1:shift)] } # end of function # Test the function Cycle(1:8, 5) # 6 7 8 1 2 3 4 5 Cycle(letters, 8) is.integer(5) # FALSE # cannot be used as criterion in function is.integer(5:6) # TRUE # see ?":" typeof(5) # double # Wat use is this function, you may wonder... # read on 😉 # Draw polygon with n corners n_gon <- function(n) { # function start op <- par(mar=rep(0,4)) # don't mess with other people's graphics: # assign the current par and reset it at the end of your function. # Keep track of what's going on: # the next line creates n vertices spaced equally along the unit circle v <- data.frame(x=cos(1:n*2*pi/n), y=sin(1:n*2*pi/n)) # Set the plot, but don't plot anything plot(v, asp=1, type="n") # Here we go: the lines. see comment below about how I figured this out segments(x0=v$x, y0=v$y, x1=Cycle(v$x, floor((n-1)/2)), y1=Cycle(v$y, floor((n-1)/2)) ) # Set the old parameters again: par(op) } # end of function n_gon(8) windows(record=T) for (i in 3:30) n_gon(i) # repeatedly clicking 'page up' on this one is not recommended for epileptics: for (i in 20:300) n_gon(i) n_gon(50) # nice interference. n_gon(100) # Look at the white bands which are not really existent... # I guess this is nothing really new, but I was just wondering whether there is # any regularity behind drawing concentric polygons. I found it is necessary to # draw a line once from every vertex to the one that is (n-1)/2 vertices later. # Then I realized, I need to recycle the vector to do that. # And then I thought it nice to take this as an example of foolprofing functions # Which is really called exception handling, but foolprofing sounds cooler. # Useless as this was contentwise, I still hope you learned something... # 12.7 Beispiele für praktische Funktionen ------------------------------------- # 12.7.1 Rechteck manuell in Graphik zeichnen ---------------------------------- rechteck <- function(...){ cat("Bitte wähle den Bereich im Graphikfenster aus.", "Klicke zuerst linksoben, dann rechtsunten.\n", sep="\n") flush.console() # Damit die Aufforderung in die Console geschrieben wird # Ausgaben werden sonst gebuffert und erst am Ende der Funktion geschrieben werte <- locator(2) polygon(c(werte$x, rev(werte$x)), rep(werte$y,each=2), ...) cat("Rechteck gezeichnet.\n", "Danke Berry für diese tolle Funktion: berry-b@gmx.de.\n", sep="") } plot(rexp(300), rt(300,5)) rechteck() rechteck(col=2) # eine ähnliches Prinzip steckt hinter berryFunctions:::bzoom, siehe 12.7 rechteck(border=3, lwd=4) rechteck(border=NA, col="white") # damit kann man auch ganz gut Text löschen ?polygon # für die Argumente, die gesetzt werden können. loeschen <- function() {cat("linksobere, dann rechtsuntere Ecke klicken.\n") flush.console() ; werte <- locator(2) polygon(c(werte$x, rev(werte$x)), rep(werte$y,each=2), border=NA, col="white") } plot(rexp(300), rt(300,5)) loeschen() # 12.7.2 Gleitendes Mittel ----------------------------------------------------- # Siehe auch BerryFunctions::movAv sowie decompose sowie zoo::rollaply movav <- function(dat, steps=7) { # Funktionsanfang # halbe Fensterbreite (in eine Richtung), dabei gerade Zahlen auffangen # (soll immer ungerade sein, damit das Fenster eine definierte Mitte hat): st <- round(steps/2-.1,0) # Länge des Eingangsvektors: ld <- length(dat) # leeren Ergebnisvektor erstellen: v <- vector("numeric", ld) # Bereich für NA ermitteln (Hälfte des gleitenden Fensters am Anfang + Ende) # bei Standard 7 steps erste und letzte drei Werte jeweils := NA v[c(1:st, (ld-st+1):ld)] <- NA # für den Rest jeweils das Mittel aus dem Fenster um den einzelnen Wert herum for(i in (st+1):(ld-st)) v[i]= mean(dat[(i-st):(i+st)],na.rm=TRUE) return(v) # Ergebnisausgabe } # Funktionsende set.seed(29); a <- runif(60, 5,50) data.frame(a[1:20], movav(a[1:20])) plot(a, type="o", pch=16, las=1) # sieht wirr aus lines(movav(a), col=2, lwd=4) # bringt Übersicht rein, zeigt Trends lines(movav(a,3), col=4, lwd=4) lines(movav(a,15), col=3, lwd=4) # unterscheidlich starke Glättung graphics.off() # Weitere Beispiele in Dokumentation library(berryFunctions); ?movAv # Visualisierung des Funktionsprinzips von movav # dir.create("MovingAverage_Funktionsprinzip") # png("MovingAverage_Funktionsprinzip/movav_%02d.png", 1024, 600) set.seed(1); a <- runif(30, 5,50) b <- movAv(a) par(mar=c(3,3,1,1), cex=2) plot(a, type="o", pch=16, las=1, ylim=c(5,55)) #blines(1:30,a) windows(record=T) for (i in 4:27) { plot(a, type="o", pch=16, las=1, ylim=c(5,55)) #blines(1:30,a) polygon(x=c(i-4,i-4,i+3,i+3)+0.5, y=c(5,55,55,5), col=rgb(1,0,0, alpha=0.2), border=2) #blines(1:(i-1), b[1:(i-1)], type="o", pch=16, col=2, lwd=3) points(i, b[i], pch=16, col=2) } # mit PgUp und PgDn (Bild hoch und runter)-Tasten Bildersequenz ablaufen lassen windows() plot(a, type="o", pch=16, las=1, ylim=c(5,55)) lines(1:30, b, type="o", pch=16, col=2, lwd=3) # dev.off() # 12.7.3 Fonttester ------------------------------------------------------------ fonttester <- function(f){ par(mar=c(0,0,0,0)) plot(0:100, rep(0,101), type="n", ylim=c(-0.3,2.8)) ; cx <- 1.5 text(0,2.5, "A B C D E F G H I J K L", adj=0 ,cex=cx) text(33,2.5, "M N O P Q R S T U V W X", adj=0 ,cex=cx) text(66,2.5, "Y Z ! ' § $ % & / ( ) =", adj=0 ,cex=cx) text(0,2, "a b c d e f g h i j k l", adj=0 ,cex=cx) text(33,2 , "m n o p q r s t u v w x", adj=0 ,cex=cx) text(66,2 , "y z 1 2 3 4 5 6 7 8 9 0", adj=0 ,cex=cx) text(0,1.5, "ß ´ } ] [ { \U00B3 \U00B2 @ \U20AC ' ~", adj=0 ,cex=cx) text(33,1.5, "* ü ä ö Ü Ä Ö ? # ` ^ °", adj=0 ,cex=cx) text(66,1.5, "< > | ; : . , - _ + @ \U20AC", adj=0 ,cex=cx) abline(h=1.25) ; abline(v=c(31,64)) text(0,1 , "A B C D E F G H I J K L", adj=0,font=f ,cex=cx) text(33,1 , "M N O P Q R S T U V W X", adj=0,font=f ,cex=cx) text(66,1 , "Y Z ! ' § $ % & / ( ) =", adj=0,font=f ,cex=cx) text(0,0.5, "a b c d e f g h i j k l", adj=0,font=f ,cex=cx) text(33,0.5, "m n o p q r s t u v w x", adj=0,font=f ,cex=cx) text(66,0.5, "y z 1 2 3 4 5 6 7 8 9 0", adj=0,font=f ,cex=cx) text(0,0 , "ß ´ } ] [ { \U00B3 \U00B2 @ \U20AC ' ~", adj=0,font=f ,cex=cx) text(33,0 , "* ü ä ö Ü Ä Ö ? # ` ^ °", adj=0,font=f ,cex=cx) text(66,0 , "< > | ; : . , - _ + @ \U20AC", adj=0,font=f ,cex=cx) text(102,2.5, paste("font =",f), adj=1, font=2) text(98,1.8,"ß", font=5, cex=3) } fonttester(5) png("fonts%02d.png", width=1000, height=200, units="px") for(i in 1:40) fonttester(i) dev.off() # 12.7.4 SCS Verfahren zur Bestimmung des Abfussbeiwertes ---------------------- Neff <- function(N) { CN <- 0:100; neff <- (N-5080/CN+50.8)^2/(N+20320/CN-203.2) par(mar=c(3.2,3,3,3.5)) plot(CN, neff, xlim=c(CN[which(neff<=N)[1]],100),ylim=c(0,N), main="EffektivNiederschlag in Abhängigkeit des CN-Faktors", type="l", las=1, mgp=c(2,1,0), yaxs="i", xaxs="i") legend("topleft", paste("Niederschlag =", N, "mm"), bg="white") axis(4,seq(0,N,len=11)[c(1,3,5,7,9,11)],c(0,2,4,6,8,10)*10, col.axis=2, las=1) mtext("Abflussbeiwert Psi",4,2, col=2)} Neff(N=15) windows(record=T) plot(1, type="n", xlab="CN", ylab="Neff [mm]", xlim=c(0,110), ylim=c(3,100), main="EffektivNiederschlag in Abhängigkeit des CN-Faktors", las=1) CN <- 1:100 for (N in 1:10*10) { neff <- (N-5080/CN+50.8)^2/(N+20320/CN-203.2) lines(CN[which(neff<=N)],neff[which(neff<=N)], col=N/10) } for (i in 1:10*10) { text(101,i, paste(i,"mm"), col=i/10, adj=0) } text(95,100, adj=1, "bei Niederschlag =") ; text(40,50,"Neff = ", adj=1) text(40,50,"(N-5080/CN+50.8)^2 /\n(N+20320/CN-203.2)", adj=0) # plot(1, type="n", xlab="CN", ylab="Neff [mm]", xlim=c(0,110), ylim=c(3,100), main="EffektivNiederschlag in Abhängigkeit des CN-Faktors", las=1) CN <- 1:100 for (N in 1:10*10) { neff <- (N-1270/CN+12.7)^2/(N+24130/CN-241.3) lines(CN[which(neff<=N)],neff[which(neff<=N)], col=N/10) } for (i in 1:10*10) { text(101,i, paste(i,"mm"), col=i/10, adj=0) } text(95,100, adj=1, "bei Niederschlag =") ; text(40,50,"Neff = ", adj=1) text(40,50,"(N-1270/CN+12.7)^2 /\n(N+24130/CN-241.3)", adj=0) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 13: Zeit und Datum ################################################# # 13.1 Datumsformat einlesen und formatieren # 13.2 Zeitformat einlesen und formatieren # 13.3 Plot und Achsenbeschriftung # 13.4 Zeitreihen aggregieren # 13.5 Hydrologisches Jahr # 13.6 nicht-equidistante Zeitreihen # 13.7 Übungsaufgaben # 13.8 Lösungen Übungsaufgaben # Beispieldaten erzeugen: Daten <- read.table(as.is=T, header=T, text=" Datum Zeit Wert 21.01.2009 13:30:00 19 21.01.2009 13:45:00 28 21.01.2009 14:00:00 17 21.01.2009 14:15:00 29 21.01.2009 14:30:00 24 21.01.2009 14:45:00 34 21.01.2009 15:00:00 28 21.01.2009 15:15:00 12") # 13.1 Datumsformat einlesen und formatieren ----------------------------------- zeit1 <- as.Date(Daten[,1], format="%d.%m.%Y") # alternative Formate "%m-%d-%Y" "%Y/%m/%d" usw. class(zeit1) ; as.numeric(zeit1) # intern ganze Zahlen für Tage seit 1970-01-01 as.Date("20090921","%Y%m%d") # geht auch ohne Leerzeichen xyz <- c("2014-02","2014-04","2015-07","2015-11") # Datumsreihen im Format mm.yyyy einlesen geht nicht mit as.Date( xyz , "%Y-%m") # sondern nur mit as.Date(paste0("01.",xyz), "%d.%Y-%m") # Datumsobjekte brauchen immer einen Tag # locale-specific sind Sachen wie %A, die auf jedem Sys.getlocale() anders sind: format(Sys.Date(), "%a %d.%b.%Y (= ein %A im %B)") # Mehr Formate unter Details in der Hilfe von ?strptime format(Sys.time(), " %H Uhr %M") format(Sys.Date(), "%A, der %d. %b im Jahre %Y") tenweeks <- seq(Sys.Date(), length.out=10, by="1 week") # next ten weeks tenweeks weekdays(Sys.Date()) months(tenweeks) # Exakt 1 Jahr zum Datum dazu addieren: k1 <- as.Date("15.3.2007", "%d.%m.%Y") k1 k1 + 1 k1 + 365 # geht nicht bei Schaltjahren. workaround: k2 <- paste(as.numeric(format(k, "%Y"))+1 , format(k, "%m-%d") , sep="-" ) k2 # es gibt aber mit Sicherheit eine einfachere Lösung... k2 + 7 # geht noch nicht, denn: mode(k2) # k2 ist kein Datum, sondern character k3 <- as.Date(k2, "%Y-%m-%d") k3 mode(k3) # zeigt numeric, denn intern ist ein Datum, wie bei Excel, eine Zahl class(k3) k3 + 7 # 13.2 Zeitformat einlesen und formatieren ------------------------------------- # Bei Uhrzeit (strptime bedeutet sowas wie string parse time) zeit2 <- strptime(Daten[,2], format="%H:%M:%S") # format ist für input # automatisch wird das aktuelle Datum hinzugefügt class(zeit2) # Portable Operating System Interface = POSIX: internat. Standard as.numeric(zeit2) # Ganze Zahlen für Sekunden seit 1970-01-01 01:00:00 CET # Bei Datum und Uhrzeit in 2 Spalten: Spalten mit paste zusammenfügen Zeit <- strptime( paste(Daten[,1],Daten[,2]) , "%d.%m.%Y %H:%M:%S") data.frame(Zeit) str(Zeit) # ein POSIX long time Objekt # Abkürzungen: "%Y-%m-%d %H:%M" = "%F %R" format(Sys.time(), "%F %T") # "2014-12-04 12:49:37" # Ausgabe formatieren (z.B. für Achsenbeschriftungen) format(Zeit, "%H:%M") # alternativ lässt sich hier auch strftime (string format time) benutzen. strftime(Zeit, "%d.%m., %H:%M:%S") #format ist für output ?strftime # für eine ganze Reihe von Formatvorlagen inkl Wochentag etc. # Einzelne Komponenten aus Daten herausnehmen: format(Zeit, "%M") which( format(Zeit, "%M")==15 ) Daten[ format(Zeit, "%M")==15 , ] # Zeitreihen anfa <- as.Date("2007/07/18") ende <- as.Date("2007/08/05") anfa; ende seq(anfa, ende, by="day") # berücksichtigt Schaltjahre strftime(anfa, "%b") strftime(anfa, "%B") # Zeitobjekt in Spalte einfügen ging früher nicht bei POSIXlt Daten$Zeit2 <- Zeit Daten$Zeit2 <- as.POSIXct(Zeit) # hätte man früher gebraucht... # 13.3 Plot und Achsenbeschriftung --------------------------------------------- plot(Zeit, Daten[,3], type="l") # Selber mit axis() Achsen beschriften ist problematisch. # bei reinem Datum geht plotten und Beschriften noch recht einfach y <- c(54, 63, 48) x <- as.Date(c("2010-08-05", "2010-08-12", "2010-08-14")) # Default format plot(x, y) plot(x, y, xaxt="n") axis(1, as.Date("7.8.2010","%d.%m.%Y"), expression( bold(hier) ) ) axis(1, x, format(x,"%d. %b\n%Y")) plot(x, y, xaxt="n") axis(1, pretty(x), format(pretty(x),"%d.%b %y")) # bei Uhrzeit geht das besser mit axis.POSIXct y2 <- c(54,63,48) d2 <- c("05.08.2010 12:13:07", "05.08.2010 12:18:54", "05.08.2010 12:29:14") x2 <- strptime(d2, "%d.%m.%Y %H:%M:%S") plot(x2, y2) # X-Achsenbeschriftung in Stunden, Minuten und Sekunden plot(x2, y2, xaxt="n") k <- "2010-08-05 12:17:00 MEZ" # automatisiert: (braucht CET: CentralEuropeanTime statt MEZ) k2 <- as.POSIXct("05.08.2010 12:26:07", "%d.%m.%Y %H:%M:%S", tz="CET") axis.POSIXct(1, at=k, format="%H:%M:%S") axis.POSIXct(1, at=k2, format="%H:%M:%S") axis.POSIXct(1, at="2010-08-05 12:22:00 MEZ", labels="hier") # oder normal mit axis, wenn mit POSIXct-Objekten gearbeitet wird: plot(x2, y2, xaxt="n") axis(1, at=k2, labels=format(k2, "%H:%M:%S") ) abline(v=as.POSIXct("2010-08-05 12:22:00 MEZ"), lty=2) # http://vmware.ie/supp # ort/developer/vc-sdk/visdk400pubs/ReferenceGuide/timezone.html # Eigene Funktion mit labels an regelmäßigen Tagen des Monats: source(url("http://dl.dropbox.com/u/4836866/BerryFunctions/R/monthLabs.R")) monthLabs() monthLabs(2014,2014, 3) # 3 days per month monthLabs(2014,2014, npy=3) # 3 months per year, equally spaced monthLabs(2014,2014, npy=4) # 4 months per year plot(as.Date(c("2013-01-05", "2015-06-9")), 1:2) plot(as.Date(c("2013-01-05", "2015-06-9")), 1:2, xaxt="n") labs <- monthLabs(2013, 2015, npy=2) # npy: number of labels per year axis(1, labs, format(labs, "%d.%m.%y") ) # 13.4 Zeitreihen aggregieren -------------------------------------------------- zr <- strptime(c("05.08.2010 12:15", "09.02.2013 14:45"), "%d.%m.%Y %H:%M") zr <- seq(zr[1], zr[2], by=15*60) # Sequenz in 15-Minuten-Schritten head(zr) tail(zr) fd <- cumsum(rnorm(length(zr))) # fake data aus Random Walk plot(zr, fd, type="l") plot(zr, fd, type="l", xaxt="n", main=c("täglicher Random Walk","")) axis.POSIXct(1, as.Date(paste0(2010:2015,"-01-01")), labels=NA) yearlabs <- as.Date(paste0(2010:2015,"-07-01")) axis.POSIXct(1, at=yearlabs, labels=format(yearlabs, "%Y"), tick=F) # Monatliche Mittelwerte ausrechnen (aggregieren): monmean <- tapply(fd, format(zr, "%Y-%m"), mean) # apply the function mean on monmean # the values fd that are first categorized into groups by month # Mittelpunkt des Monats als Datumsobjekt: monmid <- as.POSIXct(paste0(names(monmean), "-15"), format="%Y-%m-%d") lines(monmid, monmean, col=2, lwd=2) title(main=c(""," mit Monatsmittel"), col.main=2, cex.main=0.9) # Summarize daily records by quarter of the year set.seed(1492) logins <- data.frame(date=as.Date("2014-01-01")+0:364, failures=round(rlnorm(365)*20) ) # Extract month and quarter: logins$month <- strftime(logins$date, "%m") logins$qtr <- ceiling(as.numeric(logins$month)/3) # Summarize by quarter: tapply(X=logins$failures, INDEX=logins$qtr, FUN=sum) tapply(X=logins$failures, INDEX=logins$qtr, FUN=median) # unregelmäßige Messungen zu viertelstündlichen Werten aggregieren: ourdata <- data.frame(Zeit=as.character(sort(Sys.time()+rnorm(15, sd=60*30))), Wert=rexp(15)) str(ourdata) times <- strptime(ourdata[,1], format="%Y-%m-%d %H:%M", tz="Asia/Manila") # Achtung: sekunden werden hier einfach ignoriert, nicht gerundet: times$min <- ceiling(times$min/15)*15 tapply(ourdata$Wert, as.POSIXct(times), FUN=sum, na.rm=T) # für Niederschlagswerte sum, für Temperaturen mean, für Abflussmaxima max, etc. # 13.5 Hydrologisches Jahr ----------------------------------------------------- # Effizientes Programmieren ist bei langen Zeitreihen wichtig ! # Nur einmal die StringParsedTimes erstellen, und dann davon jeweils Formate # verwenden, zB beim Ermitteln der Jahresmaxima. (zr und fd aus 13.4) # Anfang hydrologisches Jahr in Deutchlands Klima: hyja <- which( format(zr,"%d.%m %H:%M") =="01.11 01:00") Max <- sapply(1:(length(hyja)-1), function(i) max(fd[ hyja[i]:(hyja[i+1]-1) ], na.rm=T)) # auch hier auf vorhandene zr zurückgreifen, und nur die gewollten auswählen Erg <- data.frame(HydroJahr=format(zr[hyja[1:length(Max)]],"%Y"), Max) Erg # 13.6 nicht-equidistante Zeitreihen ------------------------------------------- # kumulierte Niederschlagswerte set.seed(1234) # Startwert für den Zufallszahlengenerator (Reproduzierbarkeit) raindata <- data.frame(time=strptime("2011-01-28 02:08", "%Y-%m-%d %H:%M") + sort(sample(1:(400*24*3600), 150)), rain=sample(0:10, 150, replace=TRUE)) head(raindata) tail(raindata) par(mfrow=c(3,1), mar=c(4,2.5,1,0.5)) plot(raindata[ 1: 50,], xlab="2011", type="h", col=4, las=1) plot(raindata[ 51:100,], xlab="2011", type="h", col=4, las=1) plot(raindata[101:150,], xlab="2011/2012", xaxt="n", type="h", col=4, las=1) axis.POSIXct(side=1, at=monthLabs(2011,2012,npm=1), format="%b" ) # "zeitlich gebündelte" Regenfälle erkennbar monthly_rain <- tapply(raindata$rain, format(raindata$time, "%Y-%m"), sum) monthly_rain monthly_rain <- monthly_rain[-1] # Januar entfernen, weil nur 1 Wert par(mfrow=c(1,1), mar=c(5.5,4,2,0.5), lend="butt") plot(monthly_rain, type="n", las=1, xlab="", ylab="Niederschlagssumme", xaxt="n", main="Niederschlag", mgp=c(2.5, 1, 0), ylim=c(0, max(monthly_rain)*1.04), yaxs="i") abline(h=0:6*20, col=8) ; box() points(monthly_rain, type="h", col=4, lwd=11) # kann man auch mit barplot machen axis(1, 1:13, names(monthly_rain), las=2, tick=F, mgp=c(3,.5,0)) title(xlab="Monat", mgp=c(4,1,0)) # mgp[1] ist für Abstand des Achsentitels # 13.7 Übungsaufgaben ---------------------------------------------------------- # 1. In welchen Jahren seit der Wende war der 15.10. ein Mittwoch? # (Lässt sich mit 75 Zeichen in zwei Kommandozeilen herausfinden) # 2. Ignorieren Sequenzen mit 20 minuten Abstand die Schaltsekunden? # 3. Lese ein Datum ein, das wie folgt formatiert ist: "110809" (9.Aug.2011) # Ausgehend davon, erstelle eine Sequenz von einer Stunde im Sekundenabstand # 4. Schreibe eine Funktion die abhängig vom Geburtszeitpunkt dein Alter in # Sekunden, Minuten, Stunden, Tage, Wochen, Monate, Jahre ausgibt. # Optional: formatiere alle zahlen schick rechtsbündig untereinander. # Stelle fest, wann du runde Jubiläen in den jeweiligen Einheiten feierst. # Wann überholte dein Alter in Minuten die Weltbevölkerung? # 5. Oftmals sind lange Zeitreihen nicht äquidistant: # an welchen Stellen liegen Unterbrechungen vor und wie groß sind diese? # Gib den Unterschied auch in Stunden an. anfang <- strptime("05.08.2010 18:15:00", "%d.%m.%Y %H:%M:%S") set.seed(42) ; zeitreihe1 <- anfang + c(0:5*15, sort(runif(25, 60, 600000))) # Zeige die Zeitpunkte nach denen Messungen fehlen, mit Dauer der Lücke dahinter zeitreihe2 <- ( anfang + 0:200*5*60 ) [-runif(30,1,201)] # 13.8 Lösungen Übungsaufgaben ------------------------------------------------- # Aufg1: Wochentage d <- as.Date(paste(1990:2014, "10-15", sep="-")) d[ format(d, "%a") == "Mi"] # 1997, 2003, 2008, 2014 # Aufg2: Sequenzen, Schaltsekunden tail(.leap.seconds) kk <- strptime(c("2012-06-30 23:20", "2012-07-01 03:20"), "%Y-%m-%d %H:%M") seq(from=kk[1], to=kk[2], by=20*60 ) # ignoriert sie (Minuten sind noch Rund) kk[1] + 1:12*20*60 # ditto data.frame(k=strptime("2012-07-01 01:59:50", "%Y-%m-%d %H:%M:%S") + 1:20) # Mein System ignoriert die, wie erklärt unter Details der Hilfe zu ?.leap.seconds # Aufg3: Formatkonvertierungen myDate <- as.POSIXct("110809", format = "%y%m%d") myDate head(myDate + 0:3600) # Aufg4: Alter alter <- function(geburt, abfrage=Sys.time(), units=c("s","m","h","d","w")) { weite <- function(k) {ifelse(k>=1e9, 14, ifelse(k>=1e6, 15, ifelse(k>=1e3, 16, 17)))} oldopt <- options(scipen=10) for (i in 1:length(units)) { k <- difftime(abfrage, strptime(geburt, "%Y-%m-%d %H:%M"), units=units[i]) cat(format(k, big.mark=" ", nsmall=2, digits=2, width=weite(k)), "\n") } k <- difftime(abfrage, strptime(geburt, "%Y-%m-%d %H:%M"), units="d") cat(format(as.numeric(k2 <- k/(365.2425/12)), big.mark=" ", nsmall=2, digits=2, width=weite(k2)), "months \n") k <- difftime(abfrage, strptime(geburt, "%Y-%m-%d %H:%M"), units="d") cat(format(as.numeric(k2 <- k/365.2425), big.mark=" ", nsmall=2, digits=2, width=weite(k2)), "years \n") options(oldopt) } alter(geburt="2005-08-11 07:05") pretty(736435817.66) 1e9/3600/24/365.2425 # 1 billion (dt: milliarde) sekunden in 31.7 Jahren 13e6 /60/24/365.2425 # 13 Mio Minuten bei 24.7 Jahren # Aufg5: Lücken diff(zeitreihe1) difftime(zeitreihe1[-1], zeitreihe1[-length(zeitreihe1)], units="h") data.frame(Luecke_Nach=zeitreihe2[-length(zeitreihe2)], Lueckenlaenge=diff(zeitreihe2))[diff(zeitreihe2)!=5,] -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 14: Regression (Quadratmittelapproximation) ######################## # 14.1 lineare Regression (Anpassung einer Gerade an Wertepaare) # 14.2 Geradengleichung ermitteln und verwenden # 14.3 logarithmische Regression # 14.4 multivariate Regression # 14.5 cubic regression # 14.6 Funktion # 14.1 lineare Regression (Anpassung einer Gerade an Wertepaare) --------------- x <- c(5,8,10,9,13,6,2) ; y <- c(567,543,587,601,596,533,512) plot(x,y, las=1, pch=16) modellgerade <- lm(y~x) # y abh. von x. xy-Reihenfolge anders als sonst meist! modellgerade ?formula # lm(y~x): lineares Modell mit y abhängig von x # y = a*x + b, a = Steigung (slope), b = Konstante, Achsenabschnitt (intercept) # y: abhängige (dependent) Variable , criterion / response # x: erklärende unabhängige (independent) Variable , predictor summary(modellgerade) # Zur Interpretation siehe zB: browseURL("http://blog.yhathq.com/posts/r-lm-summary.html") # http://stats.stackexchange.com/questions/5135/interpretation-of-rs-lm-output # Siehe 9.1 Hypothesentests Allgemein # Nullhypothese beim Linearen Modell: Zusammenhang zufällig ("Rauschen") # Also ist p die Wahrscheinlichkeit, dass der Parameter (die Variable) # - das Modell nicht verbessert (multivariate Regression) # - und nicht zur Erklärung von y relevant ist. # Wenn p < alpha (oft = 0.05): Variable drin lassen. Es gibt einen Grund für die # Korrelation, auch wenn R^2 gering ist ("Signal") # Ziel LinMod: R2 hoch, Anzahl Parameter klein (Parsimonie prinzip, aka # Ockhams Razor: so viele Variablen wie nötig, so wenige wie möglich). str(modellgerade) # sämtliche Info, die im Objekt enthalten ist! abline(modellgerade, lwd=3, col=4) cor(x, y) # A high correlation does NOT imply correct causation! # the strong negative correlation childbirth ~ stork abundancy does not mean # getting more storks to breed here will help us fight demographic change 😉 cov(x,y)/(sd(x)*sd(y)) # Kovarianz durch Standardabweichungen cor(x, y)^2 # = R^2 summary(modellgerade)$r.square # 0.6685065 p <- predict(modellgerade) p # Achtung, für jeweilige x-Punkte, aber in aufsteigender Reihenfolge! points(x, predict(modellgerade), col=2, pch=16) # Beim lm wird die Summe der Distanzen zum Quadrat minimiert: segments(x, y, x, p) # oder umständlich: for (i in 1:7) lines( x=c(x[i], x[i]), y=c(y[i], p[i]) ) text(x, (y+p)/2, round(y-p,1), adj=-0.2) # Die Linien stellen die Residuen (Restfehler) dar residuals(modellgerade) sum((y-p)^2) # 2328.884 SSE (Sum of Squared Errors) oder RSS: (Residual SS) sum((p-mean(y))^2)/sum((y-mean(y))^2) # Variation Regresswerte / Variation Y 1 - sum((y-p)^2)/sum((y-mean(y))^2) # Unsicherheit: plot(x,y, las=1, pch=16) ; abline(modellgerade, lwd=3, col=4) x2 <- seq(1, 14, length=30) p2 <- predict(modellgerade, newdata=data.frame(x=x2), interval="confidence" ) polygon(x=c(x2, rev(x2)), y=c(p2[,2], rev(p2[,3])), col=rgb(0.3,0.5,0, 0.5)) # ANOVA # mehr zu ANOVA im Kapitel 9.5 anova(modellgerade) summary(anova(modellgerade)) # 14.2 Geradengleichung ermitteln und verwenden -------------------------------- # bei jedem ersten Durchlauf an jedem Rechner gleiche "Zufallszahlen" set.seed(12) x <- c(runif(100,0,3), runif(200, 3, 25)) # random aus uniformer Verteilung y <- 12.367*log10(x)+7.603+rnorm(300) # random aus Normalverteilung plot(x, y, las=1, pch=20, main="Verdeutlichung lin.regr. vs. log.regr.") # Koeffizienten des linearen Regressionsmodells bestimmen linmod <- lm( y ~ x ) linmod str(linmod) # Liste mit 12 Elementen abline(linmod, col=2, lwd=3) summary(linmod) r <- round( summary(linmod)$r.squared ,2) m <- round( coef(linmod)[2] ,2 ) # runde die zweite Koefiziente auf 2 Stellen b <- round( coef(linmod)[1] ,2 ) Txt <- paste("y =", m, "* x +", b, "\nR\U00B2 =", r) #\n macht Zeilenumbruch Txt text(12,10, Txt, adj=0, col=2) # Predict predict(linmod) # Standardmäßig für Werte, an denen gefitted wurde predict(linmod, newdata=data.frame(x=seq(0,20,by=4))) # colnames() des Dataframes muss genau den Namen enthalten, der auch für # lm verwendet wurde... # 14.3 logarithmische Regression ----------------------------------------------- # Koeffizienten des logarithmischen Regressionsmodells bestimmen # Achtung: log berechnet ln (Log zur Basis e), log10 den dekadischen Logarithmus # Negative Werte ersetzen, sonst können wir keinen Logarithmus berechnen # x <- replace(x, x <= 0, 0.0001) # in den Beispieldaten nicht nötig # ist eine Veränderung der Daten und daher nur begründet anzuwenden! set.seed(12) x <- c(runif(100,0,3), runif(200, 3, 25)) # random aus uniformer Verteilung y <- 12.367*log10(x)+7.603+rnorm(300) # random aus Normalverteilung plot(x,y) logmod <- lm( y ~ log10(x) ) ; summary(logmod) r2 <- round( summary(logmod)$r.squared ,2) m2 <- round( coef(logmod)[2] ,2 ) b2 <- round( coef(logmod)[1] ,2 ) xvekt <- seq(0,35,0.01) lines(xvekt, m2*log10(xvekt)+b2, col=4, lwd=3) text(12,5, paste("y=", m2, "* log(x) +", b2, "\nR\U00B2 =", r2), adj=0, col=4) # 14.4 multivariate Regression ------------------------------------------------- # Regression mit mehreren erklärenden Variablen A,B,C # Syntax (Pseudo-code): lm(y ~ A + B + C) #mit Transformationen müsste sowas gehen: lm( y ~ A + I(log(B)) + C) browseURL("http://dl.dropboxusercontent.com/u/4836866/Sonstiges/lakes.txt") lakes <- read.table("Daten/14_lakes.txt", header=T ) pairs(lakes) textcor <- function(x,y) legend("center", legend=round(cor(x,y),2), cex=2, bty="n", adj=0.4) pairs(lakes, lower.panel=textcor) summary( lm(chlorophyll ~ P, data=lakes) )$r.squared # 0.77 summary( lm(chlorophyll ~ P + N + temp, data=lakes) )$r.squared # 0.79 # R^2 etwas höher, aber: summary( lm(chlorophyll ~ P + N + temp, data=lakes) ) # Von 3 Variablen nur einer, der signifikant einen Anteil der Varianz erklärt. # Nach Ockhams Razor (Sparsamkeitsprinzip) werden die anderen beiden weggelassen # "Steht man vor der Wahl mehrerer möglicher Erklärungen für dasselbe Phänomen, # soll man diejenige bevorzugen, die mit der geringsten Anzahl an Hypothesen # auskommt und somit die 'einfachste' Theorie darstellt." [Wikipedia] # Also sukzessive die Variable mit dem höchsten P-value rauslassen, # dabei die Änderung des R2 etwas mit im Blick behalten. # Siehe Hinweis Zeile 30. cor(lakes$N, lakes$P) # erklärende Variablen sind untereinander korreliert. pnt_mod <- lm(chlorophyll ~ P + N + temp, data=lakes) pnt_mod # chlorophyll = 0.34*P + 1.14*N + 2.97*t - 33.7 K <- coef(pnt_mod) K K[2] # ist ein Vector, auch wenn es wie ein data.frame aussieht class(K) # numeric # Schätze die Chlorophyllkonzentration für eine Messung mit P=100, N=15, t=9 K[1] + 100*K[2] + 15*K[3] + 9*K[4] # 44 # zeigt als Namen den ersten Namen von k an, daher as.vector( K[1] + 100*K[2] + 15*K[3] + 9*K[4] ) View(data.frame(lakes, Chl_ESTIMATE=0.3409*P + 1.1403*N + 2.9687*temp -33.7333)) # Random Forest - wichtigkeit einzelner Prädiktoren set.seed(131) ozone.rf <- randomForest(Ozone ~ ., data=airquality, mtry=3, importance=TRUE, na.action=na.omit) print(ozone.rf) ## Show "importance" of variables: higher value means more important: round(importance(ozone.rf), 2) # Correlation matrix: round(abs(cor(airquality, use="complete")), 2) # compare cor and imp correlation <- c(0.35,0.61,0.70,0.14,0.01) importance <- c(11.97,23.22,45.22,2.10,2.83) berryFunctions::linReg(correlation, importance) # 14.5 cubic regression -------------------------------------------------------- a <- c(-5:7, 10) ; b <- 5*a^3 + 2*a^2 - 7*a + 3 + rnorm(14, 0, 100) data.frame(a,b) ; plot(a,b) modell <- lm(b ~ poly(a,3, raw=T)) ; modell # gleich mehr zu raw lines(a, predict(modell)) xdraw <- seq(3, 11, length=1e4) lines(xdraw, predict(modell, data.frame(a=xdraw)), col=2) coef(modell) dummy.coef(modell) poly(a,3, raw=T) poly(a,3) # Beim Default-Wert von Raw (FALSE) wird normiert! i <- seq (-5,10,0.1) ; j <- 3*i^2 - 5*i + 4 lm(j ~ poly(i,2)) # kommt was falsches bei rum lm(j ~ poly(i,2,raw=T)) # jetzt richtig # eine andere Möglichkeit, "+" auch für multivariate Regression: lm(b ~ I(a^3) + I(a^2) + a) # 14.6 Funktion ---------------------------------------------------------------- # Mit Funktion Werte in die Graphik schreiben (toll für Rprofile oder Paket) linreg <- function(x,y, pos="top", new=TRUE, pch=20, col=2, lwd=3, inset=0, ...) { if (new) plot(x, y, las=1, pch=pch, ...) mod <- lm( y ~ x ) abline(mod, col=col, lwd=lwd, ...) r <- round( summary(mod)$r.squared ,2) m <- round( coef(mod)[2] ,2 ) b <- round( coef(mod)[1] ,2 ) Txt <- paste0("y = ", m ," * x ", if(b>0)" + ", b, "\nR\U00B2 = ", r) legend(pos, Txt, bty="n", text.col=col, inset=inset) } # linreg(x, y, new=FALSE) fügt die Werte einem bestehenden (!) Plot hinzu # Wäre leicht um ein digits-Argument für die Nachkommastellen zu erweitern. a <- 1:30 b <- a/2.345+rnorm(30,0,3) linreg(a,b, ylab="Hallo", pch=1, col=3) plot(a,b, xlim=c(-5,45)) linreg(a, b, pos="bottomright", new=F, inset=.1) # inset für Abstand vom Rand -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 15: Extremwertstatistik für Hochwassermaxima ####################### # 15.1 Datensatz # 15.2 Jährlichkeit berechnen # Exkurs: Verschiedene Methoden zur Bestimmung der PP # 15.3 Verteilung anpassen # 15.4 Zeichnen der Abflüsse über ihre Jährlichkeiten # 15.5 Abflüsse für bestimmte Jährlichkeiten # 15.6 Funktion mit mehreren Verteilungen : L-Momente # 15.7 Funktion distLextreme # 15.8 andere Datensätze # Ich bin kein Experte für Verteilungsfunktionen, sämtliche Kommentare sind also # bitte mit Vorsicht zu genießen... # In meinem Paket sind einige hier benötigte Funktionen: movAv install.packages("berryFunctions") ; library(berryFunctions) # 15.1 Datensatz --------------------------------------------------------------- # Jahresmaxima des Abflusses 1976-2010 an einem Bach in Österreich. JM <- c(61.5, 77.0, 37.0, 69.3, 75.6, 74.9, 43.7, 50.8, 55.6, 84.1, 43.6, 81.9, 60.1, 72.4, 61.6, 94.8, 82.6, 57.2, 63.1, 73.8, 51.3, 93.6, 56.9, 52.1, 40.4, 48.9, 113.6, 35.4, 40.1, 89.6, 47.8, 57.6, 38.9, 69.7, 110.8) # Dies müssen unbedingt unabhängig voneinander sein! Es darf keine # Jahrestrennung an einem Extremereignis erfolgen (das dann in beiden Jahren # als Jahresmaxima auftaucht). # Zeitreihe anschauen plot(1976:2010, JM, type="l", las=1, ylab="Jahresmaxima Abfluss [m\U00B3/s]") # Moving Average (in berryFunctions): lines(1976:2010, movAv(JM), col=2, lwd=3) # kann ein Indikator für Trends oder # Zyklizitäten sein, aber: Fensterbreite = "researcher degree of freedom" # Wer die Theorie hinter der Extremwertstatistik schon kennt, kann gleich zu # 15.7 springen. Ansonsten soll das Folgende einen Eindruck vermitteln... # Wie immer ist Feedback sehr willkommen! # 15.2 Jährlichkeit berechnen -------------------------------------------------- quantile(JM) # 75% der Werte sind kleiner als 76.3 m3/s (oberes Quartil) # Dieser Abfluss wird in 25 von 100 Jahren überschritten, kann also statistisch # gesehen alle 4 Jahre auftreten (bei gleichbleibendem Abflussregime). # Bestimmung der Plotting Positions (PP). Früher verwendet zur grafischen # Anpassung der Extremwertverteilung als Gerade auf Gumbel-skalierter Achse # Plotting Positions nach Weibull: m <- sort(JM) # aufsteigend sortierte Maxima Rang <- 1:length(m) Pu <- Rang / (length(m)+1) # empirische Unterschreitungswahrsch. = Perzentil par(mfrow=c(1,2)) plot(m,Pu, xlab="Abflusswert", ylab="Unterschreitungshäufigkeit", las=1) # Vergleichend die empirische kumulierte Wahrscheinlichkeitsdichte: plot(ecdf(JM)) # inhaltlich fast das gleiche, jedoch von 0 bis 1, also # keine Möglichkeit für noch höhere Abflüsse, die es aber gibt. # wieder zum ersten Plot: plot(m,Pu, xlab="Abflusswert", ylab="Unterschreitungshäufigkeit", las=1) # Wiederkehrintervall = Jährlichkeit = 1/Pü = 1/(1-Pu): RP <- 1/(1-Pu) # RP: Return Period plot(m,RP, xlab="Abflusswert", ylab="Wiederkehrintervall [Jahre]", las=1) # Der höchste Abflusswert hat eine Jährlichkeit von 36. # Der zweithöchste Wert wird in den 35 Jahren zweimal ge- oder übertroffen, # tritt statistisch gesehen 2x in 35 Jahren, also alle 18 Jahre auf. # Überschreitung des dritten Wertes passiert alle 12 Jahre. etc. # Diese Reziproke (1/x) Beziehung bewirkt die unintuitive Abstände zwischen den # Return Periods. # Exkurs: Verschiedene Methoden zur Bestimmung der PP -------------------------- browseURL(paste0("http://www.uni-potsdam.de/db/fsr-ggr/data/archiv/klausuren/", "Hydrologie/Extremwertstatistik.pdf")) browseURL("www.tandfonline.com/doi/abs/10.1080/03610920701653094#.U0UC7FczZqM") browseURL("http://journals.ametsoc.org/doi/abs/10.1175/JAM2349.1") browseURL(paste0("http://www.whycos.org/fck_editor/upload/File/Pacific-HYCOS/", "Surface_Waters/Estimating_Flood_Frequency.pdf")) # Plotting Positions nach Hazen (1914): # Formeln aus dem dritten Link Pu.hazen <- (Rang-0.50)/ length(m) # Plotting Positions nach Gringorten (1963) (wie in lmom:::evplot.default): Pu.gring <- (Rang-0.44)/(length(m)+0.12) # Plotting Positions nach Beard (1943): Pu.beard <- (Rang-0.31)/(length(m)+0.38) # Plotting Positions nach Weibull (1939): Pu.weibu <- Rang /(length(m)+1) RP.hazen <- 1/(1-Pu.hazen) RP.gring <- 1/(1-Pu.gring) RP.beard <- 1/(1-Pu.beard) RP.weibu <- 1/(1-Pu.weibu) legtitles <- c( "Hazen (1914) : (Rang-0.50)/ n", "Gringorten (1963): (Rang-0.44)/(n+0.12)", "Beard (1943) : (Rang-0.31)/(n+0.38)", "Weibull (1939) : Rang /(n+1)") par(mfrow=c(1,1)) plot( m, RP.hazen, las=1, type="n", main="Methoden für Plotting Positions", ylab="Wiederkehrintervall = RP = 1/(1-Pu)", xlab="Abfluss Jahresmaxima") lines(m, RP.hazen, col=1, type="o", lty=1, pch=1) lines(m, RP.gring, col=2, type="o", lty=2, pch=2) lines(m, RP.beard, col=3, type="o", lty=3, pch=3) lines(m, RP.weibu, col=4, type="o", lty=4, pch=4) par(family="mono") legend("topleft", legtitles, col=1:4, lty=1:4, pch=1:4, title="P_unterschr. =") par(family="") # macht bei den hohen Werten einen großen Unterschied! # Entsprechend dann auch in der Berechnung der n-jährlichen Abflüsse! # Hazen, Gringorton und Beard überschätzen Wiederkehrinterval und somit # unterschätzen sie das Risiko! (verglichen mit Weibull) # I tend to like the Weibull method for Plotting Positions more. # With 35 years of data, Gringorton estimates a return period of 60 years. # But if we were to take n -> Inf samples of 35, in the long run, the highest of # these values should have a recurrence interval of ~35 years. # 15.3 Verteilung anpassen ----------------------------------------------------- # Abflussvektor für die Graphik Qrg <- extendrange(m, f=0.1) Q <- seq(par("usr")[1], par("usr")[2], len=500) # Parameter der Gammaverteilung aus den Momenten der Daten bestimmen shape <- mean(m)^2/var(m) rate <- mean(m)/var(m) # Die plotting positions sind für das fitten der Verteilungen irrelevant. # Verteilung über den Bereich Q (Graphikbereich an Abflüssen) hist(m, freq=FALSE, col=3) lines(Q, dgamma(x=Q, shape=shape, rate=rate), lwd=2) # Trifft halbwegs zu... Allerdings ist das Tailing der Werte ausgeprägter! # Neben der Gammaverteilung gibt es noch eine Menge andere, zB GEV, GPD, Gumbel, # normal, exponential, logistic, usw. Siehe Abschnitt 15.6 bis 15.8 # 15.4 Zeichnen der Abflüsse über ihre Jährlichkeiten -------------------------- plot(RP, m, ylab="Discharge HQ [m\U00B3/s]", xlab="Return Period RP [a]", las=1, main="yearly Discharge Extrema / Return Period", pch=20) # Return Period für Abflussvektor nach der so parametrisierten Gammaverteilung: RPgamma <- 1/( 1- pgamma( Q, shape=shape, rate=rate) ) # Einzeichnen der Extremwertverteilung lines(RPgamma, Q) legend("right", legend=c("Jahresmaxima 1976-2010", "Gammaverteilung"), lty=c(NA,1), pch=c(20,NA)) # Schreiben der Parameter text(15,60, paste("mean =",round(mean(m),3)," sd =",round(sd(m),3)), adj=0 ) text(15,53, bquote("shape = "* mu^2/sigma*" = "*.(round(shape, 2))), adj=0 ) text(15,46, bquote("rate = " * mu/sigma * " = "*.(round(rate, 4))), adj=0 ) text(15,39, bquote("scale = "* 1/rate * " = "*.(round(1/rate,3))), adj=0 ) # Auch hier wird das Unterschätzen hoher Abflüsse deutlich! # Die Achsen sind bewusst linear skaliert - das kann man sich visuell viel # besser vorstellen. # 15.5 Abflüsse für bestimmte Jährlichkeiten ----------------------------------- ReturnYears <- c(5,10,20,50) qgamma(1-(1/ReturnYears), shape=shape, rate=rate) # 15.6 L-Momente --------------------------------------------------------------- if(!require(lmom)){install.packages("lmom");require(lmom)} # samlmu, pelgev if(!require(evd)){install.packages("evd");require(evd)} # dgev # Lineare Momente der Stichprobe momente <- samlmu(JM, sort.data=TRUE, nmom=3) momente browseURL("http://en.wikipedia.org/wiki/L-moment") # Parameter der General Extreme Value Distribution anhand der L-Momente schätzen param <- pelgev(samlmu(JM)) # PEL: Parameter Estimation L-moments param # Die Hilfe zu pelgev hat eine Übersicht der implementierten Verteilungen # Angepasste General Extreme Value Distribution einzeichnen: hist(JM, col=4, freq=FALSE, breaks=10) lines(density(JM), lwd=1, lty=2) x <- seq(20,130, len=100) lines(x, dgev(x=x,loc=param["xi"],scale=param["alpha"],shape=param["k"]), lwd=3) # Verteilung ist mäßig geeignet, auch die anderen sind auszuprobieren # Quantil der so parametrisierten GEV Verteilung (analog zu qnorm): quagev(f=0.99, param) # 99% der Werte dieser GEV Verteilung liegen unter 127.5 # Extreme Value plot mit nicht-linearer Gumbel-Achse: evplot(JM, rp.axis = TRUE, ylab= "Discharge [m\U00B3/s]") evdistq(qfunc=quagev, param, col ="black") # Wert der Verteilung für ReturnPeriod 50 Jahre finden: quagev(f=1-1/50, para=pelgev(momente)) # aus exp(-exp(log(-log(1-1/50)))) quagam(f=1-1/50, para=pelgam(momente)) # Unterschiedliche Datensätze brauchen unterschiedliche Verteilungen. # Die GEV passt nicht immer am besten! # Unsicherheit der Parameter bestimmen via Bootstrapping, hier mit Leave5Out: q99gev <- sapply(X=5:length(JM), FUN=function(i){ param <- pelgev( samlmu(JM[-((i-4):i)], sort.data = TRUE) ) evdistq(qfunc=quagev, param, col ="black") # Verteilung mit einzeichnen quagev(0.99, param) }) # 99% Quantil bestimmen und rausgeben # Da sind schon Abweichungen in der Graphik erkennbar! # Wenn man für die Berechnung des Hochwassers einer gewissen Jährlichkeit einen # Unsicherheitsbereich angeben will, ist das eine der Methoden. as.numeric(q99gev) hist(q99gev, breaks=15, col=3) # Mögliche andere Verteilungen - Generalized Pareto Distribution (GPD): plot(ecdf(JM)) lines(x, cdfgpa(x, pelgpa(samlmu(JM))), col=2) # Naja, geht so quagpa(0.99, pelgpa(samlmu(JM))) #99% der Werte dieser GPD sind < 113.6 # Das ist schon ein wenig anders als 127.5! # To-Do: wie relevant werden Verteilungen durch L-momente anders bestimmt # als durch klassische statistische Momente? # 15.7. Funktion distLextreme -------------------------------------------------- install.packages("devtools") devtools::install_github("brry/extremeStat") library(extremeStat) library(lmomco) distLextreme(JM) # 50-jähriges Ereignis anhand verschiedener Verteilungen abschätzen: Q50 <- distLextreme(JM, RPs=50, plot=FALSE)$returnlev sort(Q50[,1], decr=TRUE) # das ist eine ganze Bandbreite an Möglichkeiten... # 107 oder 132 m3/s kann schon einen relevanten Unterschied machen! # Farben der Linien und Auswahl zu plottender Verteilungen: dle <- distLextreme(JM) distLextreme(dlf=dle, coldist=heat.colors(10), nbest=15) distLextreme(dlf=dle, coldist=heat.colors(13), selection=c(4,9,1)) distLextreme(dlf=dle, coldist=1:3, selection=c(4,9,1)) distLextreme(dlf=dle, legarg=list(cex=0.5, x="bottom", box.col="red", col=3)) # Nach Anpassungsgüte gewichtetes Mittel der verschiedenen Verteilungen: ?distLextreme # Section Examples # 15.8 andere Datensätze ------------------------------------------------------- # MackenzieRiver MR <- c(26600,30300,34000,32000,29200,28300,28600,26400,28300,28800, 29000,22100,32900,31800,21600,32100,27000,24800,28000,35000,32000,25000,15800, 28800,29900,28000,25600,19700,25700,29500,26800,30000,29500) ?Nile # 100 years! evplot(MR, ylab= "Discharge [m\U00B3/s]") evdistq(qfunc=quagev, para=pelgev(samlmu(MR)), col ="black") extremeStatLmom(MR) extremeStatLmom(MR, returnParam=T) extremeStatLmom(Nile) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### Kapitel 16 - Geostatistik ################################################## # 16.0 im Kapitel benoetigte Pakete # 16.1 ESRI-Shapefiles laden und bearbeiten # 16.2 Kriging (also die eigentliche Geostatistik) # 16.3 Karten im Hintergrund # 16.0 im Kapitel benoetigte Pakete --------------------------------------------- # Runterladen der Pakete nur einmal, danach auskommentieren install.packages("geoR") install.packages("rgeos") install.packages("maptools") install.packages("tmap") install.packages("berryFunctions") install.packages("rgl") # Laden der Pakete nach jedem R-Start (oder in Rprofile, siehe Kap 10) library(maptools) # fuer ReadShapeSpatial library(geoR) # as.geodata, variog, variofit, krige.control, krige.conv, library(sp) # geoR bereits installiert legend.krige library(rgeos) # gCentroid, gArea, gUnion library(tmap) # qtm library("berryFunctions") # colPoints, classify help(package="geoR") # und library(help="geoR") data(Europe) data(World) # Karten mit richtiger Projektion: qtm(World, fill = "economy", text="iso_a3", text.size = "AREA", fill.palette="-Blues", theme = "World", fill.title="Economy") qtm(Europe, fill="gdp_cap_est", text="iso_a3", text.size="pop_est", fill.title="GDP per capita", fill.textNA="Non-European countries") class(Europe) # SpatialPolygonsDataFrame entspricht ESRI shapefile # 16.1 ESRI-Shapefiles laden und bearbeiten ------------------------------------ browseURL("srtm.csi.cgiar.org") # globales DGM browseURL("http://diva-gis.org/Data") # Grenzen aller Staaten browseURL("http://spatialreference.org/") # proj4strings # IndiaDaten fuer das Beispiel unten gibt's hier: # http://globalresourcesuae.com/www.maptell.com/index3e60.html?Itemid=159 india <- readShapeSpatial("Daten/Shapefiles/india_state.shp") # der "Fehler in getinfo.shape(fn) : Error opening SHP file" # bedeutet oft, dass das Arbeitsverzeichnis nicht richtig gesetzt ist -> getwd() # oder der Dateiname falsch geschrieben ist. -> dir() class(india) # SpatialPolygonsDataFrame # Some states are made up of more than one polygon. # State names are in the NAME column of the dataframe View(india) head(india@data) str(india[1,]) plot(india, col = india$NAME) plot(india[india$NAME == "Tamil Nadu",], col = 1:8) attr(methods(plot),"info") # sp has a plot method ?"SpatialPolygons-class" methods(class="SpatialPolygonsDataFrame") plot(india, col=seqPal(169)); axis(1);axis(2,las=1); colPointsLegend(1:169, nbin=169, col=seqPal(169)) plot(india[72,]); axis(1);axis(2,las=1) head(india[72,]@polygons[[1]]@Polygons[[1]]@coords) tail(india[72,]@polygons[[1]]@Polygons[[1]]@coords) # Extract centroid for a State (this works): gCentroid(india[india$NAME == "Tamil Nadu",]) # Error arises for this State: gCentroid(india[india$NAME == "Gujarat",]) # orphaned hole, cannot find containing polygon for hole at index 2 plot(india[india$NAME == "Gujarat",], col = 1:8) # 16.2 Kriging (also die eigentliche Geostatistik) ----------------------------- # 16.2.1 Daten Beispiel -------------------------------------------------------- x <- c(1,1,2,2,3,3,3,4,4,5,6,6,6) y <- c(4,7,3,6,2,4,6,2,6,5,1,5,7) z <- c(5,9,2,6,3,5,9,4,8,8,3,6,7) plot(x,y, pch="+", cex=z/4) colPoints(x,y,z, col=addAlpha(rainbow2(50)), cex=3) GEODATEN <- as.geodata(cbind(x,y,z)) plot(GEODATEN) # 16.2.2 Variogramm ------------------------------------------------------------ EXP_VARIOGRAMM <- variog(GEODATEN) plot(EXP_VARIOGRAMM) FIT_VARIOGRAMM <- variofit(EXP_VARIOGRAMM) lines(FIT_VARIOGRAMM) # 16.2.3 Kriging (Interpolation unter Beruecksichtigung der Semivarianz) -------- aufloesng <- 0.1 gitter <- expand.grid(seq(min(x),max(x),aufloesng),seq(min(y),max(y),aufloesng)) krico <- krige.control(type.krige="OK", obj.model=FIT_VARIOGRAMM) krobj <- krige.conv(GEODATEN, loc=gitter, krige=krico) # KRigingObjekt # 16.2.4 Farbliche Darstellung ------------------------------------------------- colPoints(x,y,z, add=F) image(krobj, col=rainbow2(100)) legend.krige(col=rainbow2(100), x.leg=c(6.2,6.7), y.leg=c(2,6), vert=T, off=-0.5, values=krobj$predict) contour(krobj, add=T) colPoints(x,y,z, col=rainbow2(100)) # verstreute Punkte nach Hoehe gefaerbt points(x,y) # 16.2.5 3D Darstellung -------------------------------------------------------- Farben <- rainbow2(100)[classify(krobj$predict)$index] library(rgl) open3d() # Fenster in Sichtweite ziehen : Maus ziehen und scrollen plot3d(gitter[,1], gitter[,2], krobj$predict, type = "p", xlab = "X", ylab = "Y", zlab = "Z", col=Farben) plot3d(gitter[,1], gitter[,2], krobj$predict, type = "s", size=1, xlab = "X", ylab = "Y", zlab = "Z", col=Farben) # Letzteres mit allen Schatten zu rendern ist ein Heidenaufwand, hab also Geduld # 16.2.6 3D Mesh (durchgaengige Oberflaeche) ------------------------------------- # aus ?mesh3d: vertices <- c( # jeweils x,y,z,winkel; siehe ?rgl::matrices -1, -1, 0, 1, 1, -1, 3, 1, 1, 1, 0, 1, -1, 1, 0, 1 ) indices <- c( 1, 2, 3, 4) open3d() shade3d( qmesh3d(vertices,indices), col=2:5 ) open3d() wire3d( qmesh3d(vertices,indices) , col=2:5, lwd=3) # jetzt fuer Beispieldaten: dummy <- data.frame(x=gitter[,1], y=gitter[,2], z=krobj$predict, w=1) vertices <- unlist(t(as.matrix(dummy))) ; rm(dummy) round(vertices[1:30],2) open3d() shade3d( qmesh3d(vertices, rep(1:4, length(vertices)/4)) ) # nimmt nur die ersten 4 Punkte... # 16.2.7 3D perspective plot --------------------------------------------------- nx <- length(seq(min(x),max(x),aufloesng)) ny <- length(seq(min(y),max(y),aufloesng)) krmat <- matrix(krobj$predict, nrow=nx) Farben <- rainbow2(100)[classify(krmat)$index] persp(1:nx, 1:ny, krmat, col=Farben) # farben stimmen nicht plot(1,1, xlim=c(1,51), ylim=c(1,61), type="n") # hier stimmts aber: for (x in 1:51) for (y in 1:61) points(x,y, col=Farben[x,y], pch=16) # mehr zu 3D-Darstelluungen in Kapitel 4.14 # 16.3 Karten im Hintergrund --------------------------------------------------- browseURL("www.java.com") # install JAVA in same bit-version as R (eg 64bit): browseURL("http://www.java.com/de/download/manual.jsp") if(!requireNamespace("OpenStreetMap")) install.packages("OpenStreetMap") library("OpenStreetMap") d <- read.table(header=TRUE, text= "lon lat elevation 13.01480 52.39975 66.93333 13.01233 52.40032 67.00000 13.00975 52.40110 64.76667") plot(lat~lon, d) bbox <- c(extendrange(d$lon), extendrange(d$lat, f=0.5)) map <- openmap(bbox[c(4,1)], bbox[c(3,2)], type="osm") par(mar=c(0,1,3,0)) plot(map, removeMargin=FALSE) points(projectMercator(d$lat,d$lon), pch=3, lwd=3) lines(projectMercator(d$lat,d$lon) ) berryFunctions::scaleBarOSM() library("mapmisc") proj4string(map) mapmisc::scaleBar(map) # doesn't work... #SDMTools::Scalebar(1448400, 6872900, distance=0.5, unit="km") map_aer <- openmap(bbox[c(4,1)], bbox[c(3,2)], type="bing") plot(map_aer, removeMargin=FALSE) points(projectMercator(d$lat,d$lon), pch=3, lwd=3, col=2, cex=1.5) # I find type="maptoolkit-topo" to work very fine as well. For all types, see browseURL("http://www.r-bloggers.com/the-openstreetmap-package-opens-up") # Project map to UTM Coordinates map_utm <- openproj(map, "+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84") plot(map_utm) axis(1, line=-2); axis(2, line=-2) # Reading GPX files, eg from apps like sportractive or OSMtracker: #install.packages("plotKML") d <- plotKML::readGPX("Filename.gpx") options(warn=0) d <- d$tracks[[1]][[1]] d$ele <- as.numeric(d$ele) #d$time <- as.POSIXct(strptime(d$time, format="%Y-%m-%dT%H:%M:%S.")) library(berryFunctions) colPoints(lon, lat, ele, data=d, add=FALSE, asp=1, lines=TRUE, pch=NA, lwd=3) d2 <- equidistPoints(lon, lat, ele, data=d, n=25) points(d2$x, d2$y, pch=3, lwd=3) # 25 segments equally along track browseURL("http://www.r-bloggers.com/stay-on-track-plotting-gps-tracks-with-r") # Reading KML files, eg from GoogleMaps: ##install.packages("maptools") d <- maptools::getKMLcoordinates("Filename.kml",ignoreAltitude=TRUE) d <- as.data.frame(do.call(rbind, d[which(sapply(d, class)=="matrix")])) colnames(d) <- c("lon","lat") head(d) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 17: Character Stings (Zeichenketten) ############################### # 17.1 Wilde Einführung # 17.2 Suchen und ersetzen # 17.3 Anwendungen Suchen und ersetzen # 17.4 Zeichen regelmäßig ersetzen, Wildcards, Regex # 17.5 Ausgabe in die Konsole # 17.6 Anführungszeichen # 17.7 in Buchformat drucken # 17.8 Google PDF Links extrahieren # 17.9 Wildes Ende (Verschiedenes) # 17.1 Wilde Einführung -------------------------------------------------------- paste("WunderbareSache", 3:5) # macht einen Vektor mit Modus character paste(2, "hot", 4, "U", sep=" ") # Standardeinstellung seperator: Leerzeichen einVektor <- 5:9 paste("SeeYouL", einVektor[4], "ter", sep="") # Auf bestehende Objekte zugreifen Buchstaben <- c("einige verschiedene", "Buch", "staben") Buchstaben length(Buchstaben) nchar(Buchstaben) paste(Buchstaben, "tolle", sep="_") paste(Buchstaben, sep="") paste(Buchstaben, collapse="") # alle Leerzeichen ersetzen (mehr in 17.2 und 17.3) Buchst <- paste(Buchstaben, collapse=""); Buchst sub(" ", "", Buchst) # substitute (ersetze) " " in Buchst mit "" # in R vordefiniert ist schon das alphabet als Objekt letters LETTERS nchar("Monster Party") # Anzahl Zeichen; " " (Leerzeichen) ist auch ein Zeichen! substring("Monster Party", first=c(1,3,5), last=c(2,5,9) ) # "t" zweifach drin substr("Monster Party", start=c(1,3,5), stop=c(2,5,7)) # kann nicht vektorisiert strsplit("Die Ärzte - Monster Party", " - ")[[1]] s <- "am Donnerstag oder Freitag" s1 <- strsplit(s, " ")[[1]] # split string into single words s2 <- sapply(strsplit(s1, ""), rev) # reverse letters in each word s3 <- sapply(s2, paste, collapse="") # combine to new words paste(s3, collapse=" ") # paste into one single string "ma gatsrennoD redo gatierF" # Backslash "\" : Escape Character # "\n" für Zeilenumbruch (newline), zB in Graphiküberschriften und -Texte # "\t" für Tabstopp, zB für write.table("path/file.txt", yourdata, sep="\t") # "\\" für Backslash als Zeichen # "\"" für " als Zeichen # "\U" für Unicode, zB.: plot(1) # Unicode symbols without "expression" mtext("\U00D8: 5.4 [\U00B0 C]", col=2) # average and degree symbol (with space) mtext(expression(paste("Temp [",degree,"C]")), adj=0) mtext("2 * 2\U00B2 = 2 \U00B3", col=2, adj=1) browseURL("http://unicode-table.com/de/") # control characters \a, \b, \f, \n, \r, \t, \v # octal and hexadecimal representations like \040 and \0x2A num <- c(3.2, 12.03, 789) num paste(num)# schneller zu tippen als as.character(num) sprintf("%5.1f", num) # C-style String Formatting: 5 Zeichen, 1 nach dem Komma sprintf("%6.1f", num) sprintf("%7.2f", num) sprintf("%07.2f", num) # pad with zeros (mit führenden Nullen füllen) sprintf(" %07.2f", num) # Leerzeichen am Anfang # 17.2 Suchen und ersetzen ----------------------------------------------------- schoko <- c("Lindor", "Ritter Sport", "Lindor","Frigor", "Milka", "More Lindor") schoko match("Milka", schoko) # wo kommt "Milka" in schoko vor? (exakter Match) grep("or", schoko) # Elemente 1,2,3 und 6 von Schoko enthalten "or" match("Lindor", schoko) # liefert nur das erste Element, das "Lindor" ist. "Lindor" %in% schoko # logische Antwort grep("Lindor", schoko) # liefert alle Teilmatches # Ersetzen (SUBstitution) sub("or", "__", schoko) # Letztes Lindor unverändert (First matches) gsub("or", "_", schoko) # alle Matches, Global SUBstitution sapply(gregexpr("or", schoko), function(x) sum(x>0)) # Wie oft komt "or" vor? Kette <- "Lange ZeichenKette" grep("g", Kette) grep("u", Kette) # schwierig in Bedingungen etc zu verwenden, daher grepl("g", Kette) # grepl vektorisiert: grepl("h|e", Kette) grepl("u", Kette) "u" %in% Kette # geht schneller grepl("t", "D:/A_Data") # liefert TRUE, wie erwartet. "t" %in% "D:/A_Data" # FALSE: %in% ist binärer Operator für match, # match liefert nur die erste exakte (komplette) Übereinstimmung. # an welchen Stellen einer Zeichenkette ist ein bestimmter Buchstabe: unlist(gregexpr("e", Kette)) # 17.3 Anwendungen Suchen und ersetzen ----------------------------------------- # Eine Funktion soll den Speicherort einer Datei nur in die Console schreiben, # wenn der Dateispeicherort nicht als kompletter Pfad genannt wurde, also # das Working Directory (Arbeitsverzeichnis) als Ort verwendet wurde: Datei <- "Beispiel.txt" if( ! ( grepl("/", Datei) | grepl("\\", Datei, fixed=T) ) ) #" cat("Hier ist deine Datei gespeichert:",getwd(),"\n") Datei <- "D:/A Data/Beispiel.txt" # analog zum obigen Vorgehen Datei <- "D:\\A Data\\Beispiel.txt" # analog zum analogen Vorgehen # Number of occurences of character # wie oft ein Buchstabe in einer Zeichenkette vorkommt # elegantere Lösungen willkommen! nocc <- function(pattern, x, ignore.case=FALSE) sum(nchar(x)-nchar(gsub(pattern,"",x,ignore.case=ignore.case)))/nchar(pattern) # nocc(pattern="M", x="Moin an diesem schoenen Morgen") # 2 nocc("m", "Moin an diesem schoenen Morgen") # 1 nocc("M", "Moin an diesem schoenen Morgen", ign=T) # 3 nocc("m", "Moin an diesem schoenen Morgen", ign=T) # 3 nocc("n", "Moin an diesem schoenen Morgen") # 5 nocc(c("M","n"), "Moin an diesem schoenen Morgen") # nicht vektorisierbar, also sapply( c("M","n"), nocc, x="Moin an diesem schoenen Morgen") nocc("n", c("Moin an diesem", "schoenen Morgen")) # gibt nur Gesamtsumme statt 2 und 3 # Lesetipp: Die Beispiele in ?chartr # Quersumme (digit sum) quersumme <- function(dat) # vektor mit (Komma-)Zahlen sapply(strsplit(sub(".","",dat,fixed=T),""), function(x)sum(as.numeric(x)) ) # quersumme(3.14159) # = 23 = 3+1+4+1+5+9 quersumme( c(9.37, 2.1) ) quersumme(1:30) plot(quersumme(1:80), type="o") # ansteigende Periodizität plot(quersumme(1:800), type="o") # Selbstähnlichkeit (Fraktalität) plot(quersumme(1:8000), type="l") # 17.4 Zeichen regelmäßig ersetzen, Wildcards, Regex --------------------------- browseURL("http://www.regular-expressions.info/rlanguage.html") x1 <- c("1.5 mg" , "50 mg" , "100 mg" , "0.5 mg") ; x1 x2 <- gsub(" mg", "", x1) ; x2 # ersetze alle " mg" in x1 mit "" (nichts) as.numeric(x2) # mit fixed=T in gsub kann man auch "[" etc (Sonderzeichen) ersetzen: x3 <- c("Konz. [mg/l]" , "Masse [g]" , "Porosität [%]" , "Anzahl [-]") ; x3 gsub(" [g]", "", x3, fixed=TRUE) # Ausflug: Introduction von Wildcards: x4 <- c("Konz." , "Masse" , "Porosi tät" , "Anzahl", "Akt ") ; x4 grep("[t]$", x4) # die Indizes aller Elemente in x4 die auf "t" enden # alternative Methode mit Wildcard im bekannten Stil (Platzhalter: "*") grep(glob2rx("*t"), x4) grep(glob2rx("*ss*"), x4) # Welche Elemente von x4 beinhalten "ss" grep("ss", x4) # macht das gleiche, nur weniger kompliziert 😉 gsub(glob2rx("*t"), "tt", x4) # mit Wildcard ganzes Element ersetzen gsub(".*t$", "tt", x4) # Hier steht das gleiche als Regular expression (?regex) gsub("[t]$", "tt", x4) # nur t zu tt ändern # zurück zu x3: Alle Einheiten entfernen (zB. um Objekte als Dateinamen zu # verwenden); ohne glob2rx, also mit Wildcard in reg exp x3 gsub(" \\[.*", "", x3) # "\\" um aus der Escape Sequenz zu escapen und "[" # analog zu fixed=T für exact matching zu nehmen; ".*" als Wildcard gsub("ss.*", "lange,so sieht_manwas", x3) # Alternativ mit strsplit x5 <- strsplit(x3, split=" [", fixed=T) ; x5 unlist(x5)[(1:length(x5))*2-1] # Sofern in den Zeichenketten keine weiteren "[" sind: # Remove trailing zeros x <- "0.710000" sub("0+$", '', x) # Remove leading and trailing white spaces x <- " middle of the string " sub("^[[:space:]]*(.*?)[[:space:]]*$", "\\1", x, perl=TRUE) sub(" +$", '', x) # nur Leerzeichen am Ende der Zeichenkette entfernen sub("^\\s+", "", x) # nur am Anfang x <- c(" -some string" , "- leading minus sign") sub("^[[-]]*", "\\1", x, perl=TRUE) # 17.5 Ausgabe in die Konsole -------------------------------------------------- a <- print(c(1:3,"Hallo")); a b <- cat(1:3,"Hallo") ; b c <- paste(1:3,"Hallo") ; c # print schreibt in die Konsole und gibt den Wert auch zurück # cat schreibt nur in die Konsole, der zugeordnete value ist NULL # cat zeigt keine Anführungsstriche! # paste schreibt, wenn zugeordnet, nichts, sondern gibt einen zusammengefügten # character Vektor zurück. Wenn nur der Befehl ausgeführt wird, gibt es das # Ergebnis an die Konsole (wie sonst bei Funktionen auch immer der Fall). # 17.6 Anführungszeichen ------------------------------------------------------- a <- "Ein \"schöner\" Text" ; a ; cat(a, "\n") plot(1, main=a) # alles Roger b <- "Ein 'noch schönerer' Text"; b ; cat(b, "\n") ; plot(1, main=b) cc <- "Ein \"toller' Text"; cc ; cat(cc, "\n") #' # http://tolstoy.newcastle.edu.au/R/help/02b/5198.html # 17.7 Dokument in Buchformat drucken ------------------------------------------ # Broschürendruck zum Falten und Durchblättern wie im Buch. # Dazu müssen die Seiten in der richtigen Reihenfolge (siehe Funktion) und # Anordnung gedruckt werden (siehe Kommentar unten). # Beispiel für 12 Seiten: 12,1,2,11,10,3,4,9,8,5,6,7 # Ungelesene Links: # http://www.helpster.de/a5-buchdruck-in-word-vorbereiten-so-gelingt-s_54969 # http://www.ehow.com/how_4915094_print-booklet-adobe.html Buchformatdruck <- function(n, sep=",") # n: number of pages in document { # sep: seperator required by printer p <- ceiling(n/4)*4 # p: number of pages including empty pages at the back d <- p/4 # d: number of double pages o <- "" # o: order of pages for(i in 1:d) o <- paste(o, p-2*(i-1), 2*i-1, 2*i, p-2*(i-1)-1, sep=",") cat(substr(o, start=2, stop=nchar(o)), "\n") } Buchformatdruck(12) Buchformatdruck(13) # hier wären leere Seiten 14 bis 16 anzuhängen # Beidseitig drucken, Drehung an langer Kante # Word 2010: # Seiten wie von Funktion angegeben # 2 Seiten pro Blatt, Seite Einrichten -> gegenüberliegende Seiten # Foxit Reader 4.3: # Printer Properties - Querformat # Print Range: Pages [Ergebnis der Funktion] # Print Handling: # Margins 0.1 in # Page Scaling fit to paper # Page Arrange multiple pages per sheet # rotate normal # page order vertical # Pages per sheet custom 2 by 1 # Autocenter on # 17.8 Google PDF Links extrahieren -------------------------------------------- # PDF-Links aus der Google-Suche sind ganz schön lang - ich hab noch keinen # anderen Weg gefunden, nur den tatsächlichen Link zu erhalten. # Die Links sehen zB so aus: googlink <- paste0("http://www.google.de/url?sa=t&rct=j&q=semilog&source=web&c", "d=7&ved=0CHgQFjAG&url=http%3A%2F%2Fwww.math.neu.edu%2Ffries%2Fsemilog-ex-hwk.", "pdf&ei=8qnZT-qUKInCtAbU6-DFCA&usg=AFQjCNEwix4dJhFfWbKj86cBv5QeysgbVA&cad=rja") library(berryFunctions) googleLink2pdf # in berryFunctions googleLink2pdf(googlink) googleLink2pdf("http://www.google.de/url?sa=t&rct=j&q=gr%C3%BC%C3%9Fe%20pdf &source=web&cd=1&ved=0CFkQFjAA&url=http%3A%2F%2Fwww.fischerverlage.de%2Fsixcms %2Fmedia.php%2F308%2FLP_978-3-10-022303-6.pdf&ei=hq_ZT7TOKI7GtAaVs5HfBw&usg= AFQjCNEfynh6ICrjiqI6D2phge7puMQzxQ&cad=rja") # 17.9 Wildes Ende (Verschiedenes) -------------------------------------------- strReverse <- function(x) sapply(lapply(strsplit(x, NULL), rev), paste, collapse="") strReverse(c("abc", "Statistics")) plot(1, type="n") text(1,1, expression(rho ~ theta)) a <- c("A_A","A_B","C_A","BB","A_Asd") a[grepl("^[AB]", a)] # Interessantes aus der grep-und-co Hilfe mit "[" und "]": grep("[a-k]", letters) # siehe Abschnitt character class in ?regex # Thema Format: as.character l <- sprintf("%02.0f",1:12) l cat(sprintf("%s is %6.2f feet tall\n", "Sven", 7.1) ) ## re-use one argument three times, show difference between %x and %X xx <- sprintf("%1$d %1$x %1$X", 0:15) xx <- matrix(xx, dimnames=list(rep("", 16), "%d%x%X")) xx noquote(format(xx, justify="right")) sprintf("%s %d", "test", 1:3) ## Double all 'a' or 'b's; "\" must be escaped, i.e., 'doubled' gsub("([ab])", "\\1_\\1_", "abc and ABC") txt <- c("The", "licenses", "for", "most", "software", "are", "designed", "to", "take", "away", "your", "freedom", "to", "share", "and", "change", "it.", "", "By", "contrast,", "the", "GNU", "General", "Public", "License", "is", "intended", "to", "guarantee", "your", "freedom", "to", "share", "and", "change", "free", "software", "--", "to", "make", "sure", "the", "software", "is", "free", "for", "all", "its", "users") grep("[gu]", txt, value = TRUE) sub("[b-e]",".", txt) -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel 18: Optimierung #################################################### # 18.1 Exp Abnahme grob anpassen # 18.2 Zu minimierende Größe: RMSE # 18.3 Zu minimierende Funktion # 18.4 Ergebnis darstellen # 18.5 RMSE abhängig von k # 18.6 Verschiedene Startwerte # 18.7 verschiedene Methoden # Parameter mit Optimierungsverfahren genauer schätzen ------------------------- # Exponentielle Temperaturabnahme im Kaffeebecher # Anmerkung: mehrere Parameter mit optim, 1 einzelner mit optimize # Daten Zeit <- c( 0.0, 2.5, 6.0, 10.0, 12.5, 13.6, 17.3, 20.3, 23.9) # Minuten Temp <- c(43.5, 41.6, 39.6, 37.6, 36.4, 36.2, 35.0, 34.1, 32.9) #°C plot(Zeit, Temp, las=1, pch=16, ylab="Wassertemperatur [°C]", xlab="Zeit [min]") # 18.1 Exp Abnahme grob anpassen ----------------------------------------------- T0 <- 44 # Anfangstemperatur Te <- 25 # Endtemperatur diff(range(Temp)) / diff(range(Zeit)) / ( mean(Temp)-Te) k <- -0.036 # Abnahmerate [1/minute] t <- seq(0, 30, by=0.1) lines(t, (T0-Te)*exp(k*t)+Te ) # gar nicht mal so schlecht param <- c(T0=44, Te=25, k=-0.036) # Anfangsparameter, später für optim # Temperaturfunktion definieren: temperaturfun <- function(p, t) { (p["T0"]-p["Te"])*exp(p["k"]*t)+p["Te"] } temperaturfun(p=param, t=5) # nach 5 Minuten lines(t, temperaturfun(p=param, t=t) , col=2 ) # gehen die gleichen Parameter wie vorhin rein # 18.2 Zu minimierende Größe: RMSE --------------------------------------------- # root mean square error: berechnet Abweichung von x1 zu x2, wird auch zur # Berechnung des R2 in einer linearen Regression verwendet rmse <- function(x1,x2) { if(length(x1) != length(x2)) stop("vectors not of equal length") sqrt( sum((x1-x2)^2)/length(x2) ) } # Funktionsende # Man könnte auch als andere Größe die Korrelation maximieren: ?cor() rmse(Temp, temperaturfun(p=param, t=Zeit) ) # 0.53 cor(Temp, temperaturfun(p=param, t=Zeit) ) # 0.9986 - schon ziemlich gut # graphisch zu sehen: geht aber noch viel besser # 18.3 Zu minimierende Funktion ------------------------------------------------ # optim braucht eine Funktion mit par als erstem Input minfun <- function(p) rmse(Temp, temperaturfun(p=p, t=Zeit)) minfun(param) # 0.53 optimized <- optim(par=param, fn=minfun) optimized # $value 0.11 Wir hatten angefangen mit 0.53, ist also deutlich verbessert data.frame(initial=param, optimized=optimized$par) # So viel hat sich nicht geändert - wir hatten ja auch sehr gute Startwerte cor(Temp, temperaturfun(p=optimized$par, t=Zeit) ) # 0.9994, vorher 0.9986 # ist nicht so die ganz geeignete Größe dafür, liefert aber auch das Richtige: maxfun <- function(p) cor(Temp, temperaturfun(p=p, t=Zeit)) optim(par=param, fn=maxfun, control=list(fnscale=-1) ) # fnscale<0: Maximierung # 18.4 Ergebnis darstellen ----------------------------------------------------- plot(Zeit, Temp, las=1, pch=16, ylab="Wassertemperatur [°C]", xlab="Zeit [min]") lines(t, temperaturfun(p=param, t=t) , col=2 ) lines(t, temperaturfun(p=optimized$par, t=t), col=1) # deutlich sichtbar verbessert legend("topright", c("observed", "initial", "optimized"), lty=c(NA,1,1), pch=c(16,NA,NA), col=c(1,2,1), inset=0.05) text(15 ,40.5, expression("y = (T0" - "Te) "%.%" "*e^("k "%.%" x")*" "+" Te")) legend(14 ,40, paste(names(optimized$par), "="), bty="n", adj=1) legend(14.5,40, round(optimized$par,3), bty="n", adj=0) # 18.5 RMSE abhängig von k ----------------------------------------------------- k_values <- seq(-0.9, 0.025, len=200) RMSerror <- rep(NA, length(k_values)) # mit den bereits optimierten anderen beiden Werten for(i in 1:length(k_values)) RMSerror[i] <- rmse(Temp, (43.419-28.372)*exp(k_values[i]*Zeit)+28.372) plot(k_values, RMSerror, type="l", las=1) # Ist jetzt aber nur eine eindimensionale Betrachtung! # 18.6 Verschiedene Startwerte ----------------------------------------- vgl_startw <- function(T0=44, Te=25, k=-0.036) {param <- c(T0=T0, Te=Te, k=k) optimized <- optim(par=param, fn=minfun) list(data.frame(initial=param, optimized=optimized$par), RMSE=optimized$value) } # Funktionsende vgl_startw() vgl_startw(k=-0.2) vgl_startw(k=-0.9) # k optim = -10.6 -> geht nicht mehr auf das richtige k zu # Zeigt, dass Startwerte sinnvoll gesetzt werden müssen!! # Systematisch Grenzen der Methode ausloten k_test <- seq(0.5, -1, length=5000) sense <- matrix(0, nrow=length(k_test), ncol=2); colnames(sense)<- c("k","RMSE") head(sense) total <- length(k_test) pb <- winProgressBar(title="progress bar", min=0, max=total) # Fortschrittsbalken hilft in langsamen for-Schleifen, evtl in Sichtweite ziehen # Linux/Mac: tkProgressBar im Paket tcltk for(i in 1:total) {sense[i,1] <- k_test[i] sense[i,2] <- vgl_startw(k=k_test[i])[[1]][3,2] setWinProgressBar(pb, i, title=paste( round(i/total*100, 0), "% done")) if(i==total) {Sys.sleep(2) ; close(pb) } } # Ende for Schleife windows() plot(sense, type="l", las=1, xlab="initial k", ylab="optimized k") abline(h=-0.049, col=2, lty=2) text(-0.8, -0.049, "real k", col=2) # 18.7 verschiedene Methoden --------------------------------------------------- # parametersatz mit nur k-Startwert falsch optim(par=c(T0=43.42, Te=28.37, k=-0.9), fn=minfun, method="Nelder-Mead")$par # Jetzt richtig, obwohl vorhin mit -0.9 falsch. (Te besser gewählt) # Findet echten Wert? optim(par=c(T0=44, Te=29, k=-0.9), fn=minfun, method="Nelder-Mead")$par # nein optim(par=c(T0=44, Te=29, k=-0.9), fn=minfun, method="BFGS")$par # ja optim(par=c(T0=44, Te=29, k=-0.9), fn=minfun, method="CG")$par # nein optim(par=c(T0=44, Te=29, k=-0.9), fn=minfun, method="SANN")$par # nein # "L-BFGS-B" und "Brent" gehen hier nicht # Bei mehr Daten ist die Wahl der Startwerte weniger problematisch -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################ ### RclickHandbuch.wordpress.com ### Berry Boessenkool ### berry-b@gmx.de ###### ### Kapitel V (Verschiedenes): Rprofile und weitere Tipps ###################### # V.1 Rprofile.site # V.2 Verschiedene Tipps # V.3 Workspace speichern # V.4 Pakete # ToDo: Info aus dem gesamten Handbuch hier bündeln # V.5 Logische Operatoren # V.6 Gleichheit Kommazahlen # V.7 Fehlermeldungen # ToDo: Sammlung Fehler und Lösungen (vielleicht in ein früheres Kapitel?) # V.1 Rprofile.site ------------------------------------------------------------ # TinnR kann mehrere Zeilen Code (bis zur nächsten Leerzeile) mit einem Klick # an R senden (R send: contiguous), braucht aber besondere Pfade dazu: .trPaths <- paste(paste(Sys.getenv('APPDATA'), '\\Tinn-R\\tmp\\', sep=''), c('', 'search.txt', 'objects.txt', 'file.r', 'selection.r', 'block.r','lines.r'),sep='') # Praktisch ist es, die Zuordnung dauerhaft an R zu übergeben. Kopiere ihn dazu # in "Rprofile.site" (im R-Programmordner (wo R installiert ist) unter "etc"). # Die Datei kann mit Editor oder Äquivalenten geöffnet werden. # Nach dem nächsten R Start können mehrere Zeilen auf einmal gesendet werden. # Siehe auch RclickHandbuch.wordpress.com/install-r/rprofile # Auch eigene Zuordnungen, zB Funktionen, lassen sich im Rprofile # speichern, und müssen dann nicht mehr jedes Mal an R geschickt werden. # Das alles geht leider nur, wenn Admin-Rechte vorliegen. # Falls nicht: erstelle ein Skript mit allen Zuweisungen mit einem sinnvollen # Namen (zB Funktionen.r), und speichere das auf der Festplatte. Dann muss nur # am Anfang jeder Sitzung einmal source("D:/Funktionen.r") ausgeführt werden. ?Rprofile # Wichtig: Sachen in Rprofile überschreiben ls(.BaseNamespaceEnv)! # Schreibe nichts da rein, was es im base von sich aus gibt! # Praktisch: Dateipfade in Rprofile speichern desktop <- ("C:/Dokumente und Einstellungen/berry/Desktop") # Danach in jedem Skript möglich: setwd(desktop) # Setze den CRAN mirror (Wo Pakete runtergeladen werden) local({r <- getOption("repos") r["CRAN"] <- "http://mirrors.softliste.de/cran" # Berlin options(repos=r)}) # leute richtig verwirren (heimlich in deren Rprofile schreiben): pi <- 3 library(fortunes); fortune(352) # oder richtig dissen: q("no") # Bitte nicht ausprobieren, wenn grad viele Objekte zugeordnet sind... # Graphiken standardmäßig mit den y-Achsenwerten aufrecht erstellen setHook("plot.new", function(...) par(las=1), "append") # Geht aber noch nicht. Ideen vor! # Note to self: ?windows.options # Examples # Mehr unter RclickHandbuch.wordpress.com/install-r/rprofile # V.2 Verschiedene Tipps ------------------------------------------------------- # Viele Tipps zum angenehmen Programmieren via TinnR finden sich hier: # https://rclickhandbuch.wordpress.com/install-r/tinn-r/ # Lange Berechnungen in der R-Konsole können mit ESC abgebrochen werden. # Diese sind daran sichtbar, das noch kein ">" in der letzten Zeile erscheint. round(17.8) as.integer(17.8) # hättst jetzt 18 erwartet, wa? # x <- -1:12 # %/%: ganze Teiler; %%: Rest (modulo operation) data.frame(x, Teiler_5=x%/%5, Rest=x%%5 ) # Spaltennamen, die mit einer Zahl beginnen, wird ein X vorgesetzt data.frame("2.7.2010"=12:18, ZweiteSpalte=18:12) # Das passiert auch bei mit read.table geladenen Dataframes! # Es kann aber ersetzt werden (praktisch zB für Subs von Boxplots): # names(Objekt) <- c("1.Tag", "2. Messung") # sogar Leerzeichen sind OK! # sourcecode von Funktionen: lm summary methods(summary) summary.table # Nachkommastellen (der Ausgabe in der RConsole) einstellen d = data.frame( a=rnorm(10) , b=rnorm(10) ) options(digits=4) # Übersichtlichkeit der Datendarstellung einstellen d print(d[1,1], digits=18) # Die Daten selbst haben noch viele Nachkommastellen. options(digits=7) # Standardeinstellung # Umgang mit NAs (Not available, unbekannt) v <- c(7,9,NA,5,6) cumsum(v) # 7 16 NA NA NA # Inhaltlich falsch, aber wenn man davon ausgeht, dass NAs 0 entsprechen: # Ersetze in v alle Werte == NA mit 0 (replace) cumsum( replace(v, is.na(v), 0) ) # 7 16 16 21 27 # Alternative: Mittelwerte der nicht-NA-Werte: cumsum(replace(v,is.na(v),mean(v, na.rm=T))) # 7.00 16.00 22.75 27.75 33.75 # V.3 Workspace speichern ------------------------------------------------------ # Beim Schließen von R braucht das WorkSpace normalerweise nicht gespeichert zu # werden, es kann ja mittels des Skripts in TinnR erneut hergestellt werden. # Spätestens nach vierstündigen Berechnungen sollte es aber gespeichert werden. # siehe dazu save(list="Objekt", file="Dateiname.RData") ?save.image # Für das gesamte Workspace, also kurz für save(list=ls(), ".RData") # mit rm("Objekt7") kann man Objekte einzeln löschen und dann save.image nutzen. load("ewaigeSubordner/Dateiname.RData") ?history # Nach solchen großen Berechnungen kann es sinnoll sein, R zu schließen und neu # zu öffnen. Siehe dazu die relative Größe der Auslagerungsdatei im Taskmanager # (STRG + ALT + ENTF), (unter Linux in der Systemüberwachung) # V.4 Pakete ------------------------------------------------------------------- library() # zeigt alle runtergeladenen und mitinstallierten packages library("datasets") library(help="datasets") # Etwas zu Paketen, Vgl auch Kapitel 4.12 library(alr3) # geht noch nicht install.packages("alr3") # nur einmal abschicken! Nicht in RProfile stecken! # jetzt wurde das Paket gedownloaded und installiert. # Aus Recheneffizenzgründen musss es aber nach jedem R-neustart geladen werden. library(alr3) # in eigenen Funktionen sollte require statt library benutzt werden. # Dann werden Fehlermeldungen a la "Wurde unter R 2.13 erstellt" unterdrückt. # V.5 Logische Operatoren ------------------------------------------------------ 2>4 !2>4 # NICHT A <- c(TRUE, TRUE, FALSE, FALSE) ; B <- c(TRUE, FALSE, TRUE, FALSE) ?"&" data.frame(A, B, Nicht_A = !A, A_und_B = A&B, A_oder_B = A|B) dat <- rnorm(300) ; hist(dat) dev.off() hist(dat, plot=F) F F <- 3 F hist(dat, plot=F) # F geht nur als Abkürzung für FALSE, solange es nicht überschrieben wird. rm(F) F # Viele Anwendungen von TRUE/FALSE auch in Bedingungen --> Kap 11.1: if dat <- sample(-6:10) dat > 4 which(dat > 4) # An welchen Stellen eines logical Vectors steht TRUE? sum(dat > 4) # Anzahl TRUE. Funktioniert, da TRUE = 1 und FALSE = 0 dat < -2 # Leerzeichen wichtig! dat <-2 würde "dat" mit der Zahl 2 überschreiben dat<(-2) # ist schlecht menschenlesbar, aber eindeutig. # V.6 Gleichheit Kommazahlen --------------------------------------------------- 0.5-0.2 == 0.3 # ja nee, is klar. Denkst du?! Dann check mal das: 0.4-0.1 == 0.3 # Grundgedanke aus "The R-Inferno" entnommen - sehr lesenswert! # Zweiteres zeigt FALSE, obwohl es richtig ist! Folgendes ist der Grund: # ein Rechner kann Fließkommazahlen nur endlich genau verarbeiten - arbeitet # mit binären Zahlen - abhängig von bit-Betriebssystem, Prozessor-Architektur, # definition des Zahlenformats (single = 1 byte = 8bit, double = 2 byte), usw. # Am Rande für Informatiker: R verwendet nur Double, siehe Note zu ?numeric. print(0.4, digits=20) print(0.1, digits=20) # Schlagwort: arithmetische Präzission print(0.3, digits=20) print(0.4-0.1 , digits=20) # Folgendes ist die Lösung für einzelne Zahlen: all.equal( 0.4 - 0.1 , 0.3 ) # TRUE (lässt PC-Ungenauigkeit zu) # Aber nicht für ganze Vektoren: set.seed(12); zahlen <- sample( 1:8+3:6/10, 30, replace=T) ; zahlen all.equal(zahlen, 4.6) # geht nicht # Wenn man z.B. das Ergebnis einer anderen Rechnung verwenden will: zahlen == 4.9-0.3 # Alles FALSEs, obwohl es 4.6 gibt! 4.9-0.3 == 4.6 # Absolute Gleichheit nicht gegeben # Lösung für Zahlenvergleich von Vektoren: # Komplizierte (aber allgemeingültige) Lösung: TF_Werte_einzeln <- by(zahlen, 1:length(zahlen), FUN=all.equal, current=4.9-0.3) welcheT <- which(TF_Werte_einzeln==T); welcheT str(TF_Werte_einzeln) str(welcheT) # welcheT hat names, aber das stört ja nicht names(welcheT) <- NULL ; welcheT # Falls es doch mal stört 😉 # einfache Lösung: which( zahlen == round(4.9-0.3, 8) ) # Problematisch, wenn mehr # Nachkommastellen wichtig sind, und man das nicht bemerkt! # Randnotiz: Runden auf signifikante Stellen, also Zahlen nach Nullen: round( 0.00314869, digits=3) signif(0.00314869, digits=3) # ANzahl notwendiger digits beim Ausgangsbeispiel: round(0.4-0.1, 20) == round(0.3, 20) # noch FALSE round(0.4-0.1, 15) == round(0.3, 15) # TRUE # Merke: niemals Fließkommazahlen einfach so auf absolute Gleichheit prüfen! # V.7 Fehlermeldungen ---------------------------------------------------------- # Unterschied Fehler und Warnung: # Fehlermeldungen treten bei Fehlern auf (Ach nee). --> Abbruch der Funktion. # Warnmeldungen sollten gelesen werden, weil die Funktion nicht abgebrochen, # sondern wahrscheinlich anders ausgeführt wird, als du willst! # häufige Fehlermeldungen: # "Unerwartete(s) Symbol" # Meistens eine Klammer noch nicht wieder geschlossen, ein Komma vergessen, etc. # Sammlung to be ausgedehnt. -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ################################################################################
0 Antworten to “AllesZurSuche”