################################################# ### Funktionen (ein erstes, wichtiges Objekt) ################################################# ### # Eine Funktion ist ein Programmkonstrukt, das eine Prozedur auf # bereitgestellten Objekten ausführt und ein Ergebnis zurückgibt. ### Beispiel für Funktionen und Funktionsargumente zahl <- 2.3 class(zahl) # numeric buchstabe <- "2.3" class(buchstabe) # character ?log # Hilfe der Funktion log log # Funktionsdefinition von log class(log) # log gehört zur Klasse "function" log() # Aufruf log ohne Angabe von Argumenten. log( x = zahl) # Man kann das das Arguments auch mit dem in der Funktion # verwendeten Namen übergeben log(zahl) # Name "x" kann weggelassen werden # Erinnerung ( getwd() und setwd() haben wir bereits benutzt, genauso help() und print() ) setwd("codes/test.r") setwd( dir = "codes/test.r") getwd("codes") # Fehler, da getwd() kein Argument akzeptiert args(log) # Beachte: 2. Funktionsargument "base" log( x = zahl, base = 10) # Logarithmus zur Basis 10 log10(x = zahl) log(base = 10, x = zahl) # Bei Argumentangabe: Reihenfolge egal! log(zahl, 10) # OHNE Angabe: VORSICHT REIHENFOLGE! log(10, zahl) a <- log(-1) # nicht definiert -> NaN (Not a number) a (b <- log(0)) class(a) class(b) b + 2 a + 2 ### Eigene Funktionen definieren # Einfache Funktion f1 <- function(x1=1,x2=2) x1*x2 # f1: Funktionsname # function(x1=1,x2=2) x1*x2: Funktionsdefinition # x1*x2: Funktionskörper (die auszuführende Abfolge an Operationen) f1 # Funktionsdefinition anzeigen lassen (print-Methode auf eine Funktion) f1() # Funktion aufrufen, allerdings verlangt diese Funktion Argumente f1(x1=2, x2=5) f1(x1=2, x2=5, y=5) # Funktion akzeptiert exakt 2 Argumente, 3 erzeugen darum einen Fehler #### Was passiert beim Aufruf der Funktion? f1(x1 = 1,x2 = 2) # Während der Laufzeit der Funktion wird eine neue Umgebung erzeugt, in dieser sind # zwei Variablen vorhanden, x1 hier mit dem Wert 1, x2 hier mit dem Wert 2. bwinÓéÀÖ_bwinÓéÀÖ¹ÙÍø»¶Ó­Äú@e werden # benutzt um das Produkt zu berechnen, dieses wird schließlich zurückgegeben. # Funktion ohne Argument (vgl. getwd()) f2 <- function() x1 * x2 x1 <- 2 x2 <- 3 f2 # Funktionsdefinition anzeigen lassen f2() # Funktion aufrufen f2(x1=2) # Erzeug einen Fehler, f2 akzeptiert kein Argument f2(2) # f2 hat keine Argumente. Das heißt aber auch, dass bei Laufzeit in der erzeugten Umgebung # auch nicht die Variablen x1 und x2 sichtbar sind. In R ist die Regel, dass dann in der # nächsthöheren Umgebung nach den Variablen x1 und x2 gesucht wird (also bspw. in der Umgebung # aus der die Funktion aufgerufen wurde. Existiert x1 und x2 in keiner Ebene, führt das zu einem # Fehler: rm(x1,x2) f2() # bwinÓéÀÖ_bwinÓéÀÖ¹ÙÍø»¶Ó­Äú@es sukzessive Suchen in höheren Ebenen wird auch Scoping genannt, Beispiel siehe weiter unten. # Funktion mit bereits vorbelegten Funktionsargumenten (optionale Funktionsargumente) f3 <- function(x1=1,x2=2) x1*x2 f3() f3(3) f3(3,4) f3(x2=3) # Meist führen Funktionen kompliziertere Operationen aus, alle Anweisungen in eine Zeile zu # schreiben ist deshalb meist unübersichtlich. Es empfiehlt sich daher, den Funktionskörper # in geschweifte Klammern {} einzuschließen: f4 <- function(x1,x2) { z <- x1 + x2 abc <- x1/z return(abc) # return gibt funktionswert aus und beendet Funktion } f4(1,2) # Beispiel Scoping: z <- 20 f5 <- function(x1){ x1^2+z } f5(1) # vs. f6 <- function(x1){ z <- 10 x1^2+z } f5(2) f6(2) # f5 sucht in der nächsthöheren Umgebung, innerhalb der Umgebung von f6 ist z ein fester Wert # Das "Dreipunkte"-Argument -> Reicht Funktionsargumente an innere Funktionen weiter f7 <- function(e, ...) { log(e, ...)^2 } # alle Argumente, mit denen f7 nichts anfangen kann, werden an log() weitergereicht log(5)^2 f7(5) log(5, base=10)^2 f7(5, base = 10) f7(5, base = 10, arg3 = "a") # mit arg3 kann aber log() auch nichts anfangen... ### Beachte: # # In R implementierte Funktionen wirken teilweise unterschiedlich, # je nachdem, auf was für ein Objektklasse sie angewandt werden (wichtiges Beispiel: plot) # Kurzer Exkurs # - auf Funktion ?plot plot(cos, -1, 1) # - auf zwei Vektoren x <- 1:5 y <- 6:10 plot(x, y) # -> Objektorientierte Programmierung # siehe weiter unten # ### Fazit: # # Alle Objekte was nicht Daten sind eine Funktion. # Was man nun wissen sollte: # Funktionsname, Funktionskörper, Funktionsdefinition # Für den Quellcode einer Funktion (R ist KEINE Blackbox!) ist # Uwe Ligges Artikel in R news (p. 43) eine gute Referenz. # # "When looking at R source code, sometimes calls to one of the following functions show up: # .C(), .Call(), .Fortran(), .External(), or .Internal() and .Primitive(). # These functions are calling entry points in compiled code such as shared objects, # static libraries or dynamic link libraries. Therefore, # it is necessary to look into the sources of the compiled code, # if complete understanding of the code is required. ... # The first step is to look up the entry point in file '$R HOME/src/main/names.c', # if the calling R function is either .Primitive() or .Internal()." # ### Aufgabe B1 # a) # Erzeugen Sie eine Funktion mit Namen "getSquaredSum", die bei Eingabe # zweier Zahlen die quadrierte Summe der Zahlen berechnet und zurückgibt. # Testen Sie diese Funktion mit zwei Möglichkeiten. # Belegen Sie nun das zweite Funktionsargument mit 0 vor. # b) # Erzeugen Sie eine Funktion, # in deren Funktionskörper eine weitere Funktion # definiert und dann aufgerufen wird. # Definieren Sie nun die "innere Funktion" # außerhalb der äußeren. Was gefällt Ihnen besser? # Ãœberprüfen Sie, ob alles funktioniert und gleiche Werte liefert! ## Test: GetSqRet1(1,2) GetSqRet2(1,2) ## Achtung!! bei folgendem Code: summe <- function(x1,x2) x1+x2 GetSqRet3 <- function(x1,x2) { z <- (x1+x2) function(z){ return(z^2) } } ## Die Funktion GetSqRet3 gibt eine Funktion zurück, die von einer Zahl das Quadrat berechnet: (result <- GetSqRet3(1,2)) result(3) ################################################# ### Atomare Datentypen (atomar, weil aus diesen Datentypen alle anderen bestehen) ################################################# NULL # die leere Menge NULL # logische Werte logical # ganze Zahlen integer # reelle Zahlen numeric # komplexe Zahlen complex # Buchstaben und Zeichenfolgen character ################################################# ### Logische Ausdrücke und Operatoren is.integer(3) is.character(3) as.character(3) is.integer(as.integer(-3)) is.integer(as.integer(3)) value1 <- TRUE value2 <- FALSE value3 <- TRUE class(value1) # value1 && value2 value1 & value2 # '&&' bzw '&' heißt "UND ZUGLEICH" value1 && value3 value2 && value2 v1 <- c(TRUE, FALSE) v2 <- c(TRUE, TRUE) v1 && v2 # vergleicht immer nur den ersten Eintrag eines Vektors v1 & v2 # vergleicht v1 und v2 elementweise und liefern wieder einen logischen Vektor !value2 # '!' ist die Verneinung ( value1 || value2 ) ( value1 || value2 ) && !value1 # '||' bedeutet "ODER" v1 || v2 # analog zu '&' vs '&&' v1 | v2 value1 == value2 # führt einen Vergleich durch (keine Definition wie '=' !!!) value1 != value2 # ist ungleich? !(value1 == value2) # äquivalent # kurze Problematik: zahl <- 2.3 buchstabe <- "2.3" zahl == buchstabe class(zahl) == class(buchstabe) value1 + value2 # Rechenoperationen betrachten TRUE als 1 und FALSE als 0 value3 <- value1+ value2 class(value3) value1*value2 # Beachte: Auch Operatorsymbole sind Funktionen! ?'==' args('==') '=='(value1,value2) '+'(value1, value2) ### Reelle und komplexe Zahlen z1 <- 4.89 z13 <- as.integer(4.89) z2 <- as.integer(3) class(z1) # Datentyp abfragen class(z2) z3 <- z1 + z2 # Einfache Berechnungen class(z3) z2^2 z4 <- 2 z3*z4 z2 > z1 # Vergleich von Werten z2 == z1 z2 > z2 class(z2 < z2) z2 >= z2 z1 <= z2 z3 <- 3 + 5i # a + ib, a, b reelle Zahlen und a Realteil, b Imaginärteil ## Defintiion von i: i^2 = -1 class(z3) a <- sqrt(-1) a (z4 <- sqrt( as.complex(-1) )) # Quadratwurzel! Ausprobieren: sqrt(-1)! z4^2 z3 z4 z3*z4 Im(z3*z4) # Imaginärteil z3*z4 = 3i - 5; (a + ib) * (c + id) = ... -bd Re(z3*z4) # Realteil einer komplexen Zehl ### Zeichenfolgen verein <- "FC Bayern" class(verein) # Datentyp abfragen paste("Test1", "test2") # Character mit Variablenbesetzungen verbinden: paste ?paste paste("Mein Lieblingsverein ist der" , verein , sep=" ") # Wichtig für Plots später paste("Mein Lieblingsverein ist der" , verein , sep="") # Wichtig für Plots später aussage <- "Mein Lieblingsverein ist der" paste(aussage, verein, sep = " ") paste(verein, verein, verein, sep="SCHLECHT") paste0(verein, verein) zahl <- 5 b <- paste(aussage , zahl , sep=" ") # numeric wird zu character konvertiert b ### Fehlende Werte class(NA) s <- NA s == 5 s == NA is.na(s) # Für jeden atomaren Datentyp gibt es eine Funktion, # die auf die Klasse prüft ?is.integer ?is.complex ?is.logical ?is.null ??"isNull" a <- as.integer("sab") a (s+5) # Jede Mathe-Operation mit einem NA führt zu einem NA ################################################# ### Datenstruktur 1: Vektor (DIE grundlegende Struktureinheit) ################################################# # Ein Vektor eine Verkettung von Objekten (nicht nur Zahlen; Concatenate = verketten) a <- c(3,6,2) # Zusammenbinden von Einzelelementen... a c(1L,3) b <- c(a,4,5,6) # ... und Vektoren zu einem Vektor b class(b) c <- c(6.9, "Bla bla", 12.7) # Vektoren haben Einträge EINES Typs # (des "niedrigsten" Datentyps) c class(c) c2 <- c(4.6,NA,22) # aber NA's ändern die Klasse nicht class(c2) class(NA) c2 d <- c(f1 = TRUE, f2 = FALSE, f3 = FALSE) # Einträge können Namen haben d class(d) e <- 1:3 # Einfache Sequenz (geht auch mit seq(...) ) e ?seq ?seq f <- seq(from = 1, to = 12, by = 0.2) # Sequenzen... f_star <- seq(from = 1 , to = 12, length.out = 100) f ?rep g <- rep(5, times = 6) # ... und Wiederholungen g h <- rep(c(1,5), times = 6) # ... auch komplizierter h h2 <- rep(c(1,5), each=5) h2 names(d) names(d) <- c("a1","a2","a3") attributes(d) # alternativ length(d) class(d) # Klasse des Vektors ist Klasse der einzelnen Komponenten ### Einzelne Elemente eines Vektors ansprechen (INDIZIERUNG) # - numerische Indizierung # - logische Indizierung # - Indizierung per Namen a <- c(2,6,3) a[2] # Numerische Indizierung a[c(1,2)] a[1:2] # schöner a[-2] # Einfache negative Indizierung: alle Werte von a ohne das 2. Element a[-c(1,2)] # Ausschluss durch mehrfache negative Indizierung a[-(1:2)] # analog zu oben # - logische Indizierung logical_index <- c(TRUE,FALSE,TRUE) # Logische Indizes a[logical_index] a[c(TRUE,FALSE,TRUE)] a[c(TRUE, FALSE)] a > 2 # R denkt dabei: Vervollständige 2 auf die Länge von a a[ a>2 ] # Hier bekommt man Werte, die größer als 2 sind a # - Indizierung per Namen d["a1"] which(a>2) # Positionsvektoren; gibt die Indizes zurück, an denen die Werte stehen # Hier bekommt man Indizes, die größer als 2 sind a[which(a>2)] which.max(a) # an der Stelle 2 steht das Maximum des Vektors a (in diesem Fall 6) a_star <- c(3,6,2,6,2) which.max(a_star) # Aufgabe B2 # Schreiben Sie eine Funktion, die die Summe zweier Vektoren berechnet und als # Wert (nicht als print-Ausgabe) den Character "Die Summe ist [Wert]" zurückgibt. # Testen sie mit den Vektoren: xy <- c(1,2,3) yx <- c(4,5,6) ################################################# ### Datenstruktur 2: Matrix ################################################# a=1 f<- c(1,2,3,4,5,6) g <- 1:6 all( f==g ) any( f==g ) class(f) ?dim() length(f) dim(f) dim(f) <- c(3,2) # Erzeugung aus Vektor mit 'dim'-Attribut (Dimension) f class(f) dim(f)[1] # Zeilenanzahl dim(f)[2] # Spaltenanzahl ## alternativ: ncol(f) # Spaltenanzahl nrow(f) # Zeilenanzahl attributes(f)$dim # zeigt die Dimensionen an dim(f) # analog A <- matrix(1:9 , ncol=3,nrow=3) # Funktion matrix() A # WICHTIG: Zuerst 1. Spalte befüllt etc. ?matrix # optionaler Parameter byrow=FALSE A <- matrix(1:9,ncol=3,nrow=3, byrow=TRUE) A B <- matrix(c(2,4,3,6,4,5,12,1,3),ncol=3,nrow=3) B C <- matrix(NA, 4, 5) # Wert (oder zu kurzer Vektor) wird wiederholt, bis Matrix voll ist C C[1,1] <- 1 D <- matrix(1:3,3,3) # befülle mit einem 3x1 Vektor eine 3x3 Matrix D E <- matrix(1:4,3,3) # nur falls die Länge der Folge ein Teiler der Zeilenlänge ist F <- matrix(1:2, 3, 2) F colnames(F) <- c("s.1","s.2") # Zeilen- und Spaltennamen rownames(F) <- c("z1.","z2.","z3.") F f["z1.", "s.2"] # Ansprechen der 1. Zeile (später noch mehr dazu) ### Spezielle Funktionen für Matrizen (cbind(A,B)) # Verknüpfungen nebeneinander (column bind) (rbind(A,B)) # ... untereinander (row bind) (cbind(1,A)) # Eintrag '1' wird wiederholt! t(A) # Transponierung ?diag() diag(nrow = 5) diag(5) diag(A) # Einheitsmatrix diag(c(1,4,3,5)) # Diagonalmatrix A diag(A) # Diagonalelemente als Vektor ?diag() # je nach Objekt, das übergeben wird, gibt es ein unterschiedliches Ergebnis str(A) # STRucture; numerische Einträge, zwei Spalten der Länge zwei, die Einträge ### Indizierung: Zeilen- UND Spaltenindex! # 1. Numerische Indizierung a <- 2:6 a[5] B B[ , ] # egal welche Zeile oder Spalte B[2,3] # 2. Zeile, 3. Spalte (ein Element) B[ ,3] # egal welche Zeile, 3. Spalte B[ c(1,3) , ] # 1. und 3. Zeile, egal welche Spalte # 2. Logische Indizierung iA <- matrix( c(TRUE , TRUE , FALSE , TRUE , TRUE ,rep(FALSE,times=4)), nrow=3, ncol=3 ) iA # Erzeuge Indexmatrix: TRUE-Werte sollen aus A matrix ausgewählt werden A A[iA] # ... wird zu Vektor! iA <- upper.tri(A, diag = TRUE ) # Die Elemente rechts der Hauptdiagonale sollen gewählt werden iA A[iA] A iA <- A>5 # Beachte: Vergleich ist Elementweise iA A[iA] # oder schneller A[A>5] # Beachte: Reihenfolge folgt spaltenweise ################# ### !WICHTIG! ### # Reduziert man mehrdimensionale Objekte auf niedrig dimensionalere Objekte # (z. B. Array -> Matrix -> Vektor) so geht die Information der zusätzlichen # Dimension im Fall "Matrix -> Vektor" verloren! B[ ,3] # 3. Spalte = eigentlich ein Spaltenvektor, hier nur noch ein einfacher Vektor class(B[ ,3]) class(B) dim(B[ ,3]) dim(B) # In längeren Programmen, ist es aber oft unklar, ob eine (und dann ein Zeilenvektor) oder # mehrere Spalten (und dann eine Matrix) indiziert werden, weswegen man mit drop = FALSE # die größere Struktur nicht "dropped" B[ ,3, drop = FALSE] class(B[ ,3, drop = FALSE] ) dim(B[ ,3, drop = FALSE] ) ################# ### Matrix- und Vektorberechnungen # Elementare Berechnungen ( + , - , * , / , ^ ) a <- c(2,6,3,8,1) b <- 5:9 b 2*a + b A B 2 * A 2 * A + B a sum(a) prod(a) cumsum(a) cumprod(a) b[-1] BB <- cbind(b, b[-1]) # VORSICHT: Kurzer Vektor wird wiederholt!!! BB e b + e b A b + A a <- 1:3 a b <- 6:8 a * b # VORSICHT: Mathematische Standard-Operatoren wirken elementweise!!! a %*% b e e^2 A^(-1) # Auch hier Achtung, '^' operiert elementweise und liefert # bei Anwendung auf eine Matrix nicht die Potenz der Matrix # sondern lediglich die Potenzen der einzelnen Einträge. sin(e) sqrt(e) A B A * B # Matrix-Multiplikation mit '%*%' A E A %*% E A %*% a A %*% B C # 4x5 Matrix A %*% C # Dimensionen müssen passen! Hier: A 3x3, C 4x5 ### Aufgabe B3 # Berechnen Sie für die Matrix A = Mat_A Mat_A <- matrix(1:9, ncol = 3) # und den Vektor b = vec_b vec_b <- 12:14 # das Matrizenprodukt Ab und das Komponentenprodukt. Erklären Sie die Unterschiede. a b t(a) %*% b # Skalarprodukt (Ergebnis ist (1x1) Matrix, außer...) # 1x3 mit 3x1 ergibt 1x1 a%*%b class(t(a)%*%b) c(t(a)%*%b) class(c(t(a)%*%b)) a%*% t(b) # Äußeres Produkt oder dyadisches Produkt # 3x1 mit 1x3 ergibt 3x3 a%*%b # VORSICHT! Im Zweifel wird Skalarprodukt ausgeführt ### Determinante und Inversion von Matrizen (S <- matrix(c(1,0.5,0.5,1),2,2)) det(S) # ad - bc, hier: 1*1 - 0.5*0.5 solve(S) # Inverse von S S %*% solve(S) # Eigenwerte und -vektoren eigen(S) ?eigen eigen(S)$values eigen(S)$vectors class(eigen(S)$values) length(eigen(S)$values) eigen(S)$values[2] eigen(S)$vectors[,2] ### Aufgabe B4 # Geben Sie die Objekte # # 3 1 4 # 5 1 3 # 2 1 7 # y = 8 und X = 1 1 # 6 1 3 # 4 1 7 # 7 1 5 # (vgl. Regressionsmodell y = X b + u mit 7 Beobachtungen und Konstante) # in R ein. # a) Geben Sie X und y für die 3. Beobachtung dieses Regressionsmodells aus. # b) Berechnen Sie X'X, X'y, (X'X)^(-1) sowie den KQ-Schätzer des linearen Regressionsmodells # y = X beta + u # c) Geben Sie unter Standardannahmen den Standardfehler der Koeffizienten an. # Hinweis: Falls Sie die Definition nicht mehr wissen, sehen Sie im Ökonometrie 1 Skript nach. # d) Erzeugen Sie eine Funktion, die bei Angabe von y und X eine Matrix mit beta und # Standardfehler als Spalten ausgibt. ### Aufgabe B5 # Geben Sie die Matrix # # A = 1.0 0.5 # 0.5 1.0 # in R ein. # Berechnen Sie die Eigenwertzerlegung von V*Lambda*V^-1, # wobei Lambda eine Diagonalmatrix mit den Eigenwerten und # V die Matrix mit den Eigenvektoren als Spalten ist. # Ist obiges Produkt gleich A? ################################################# ### Datenstrukturen 3: array (= beliebig dimensionale Matrizen) ################################################# ### Motivation: # Arrays für mehrdimensionale Auswertungen # (Bsp: Funktion in Abhängigkeit von vier Variablen -> 4 dimensionaler Array) ### Array: Mehrdimensionale "Elementsammlung" # während eine Matrix ein zweidimensionales Gebilde ist, können Arrays beliebig dimensional sein (mat <- 1:4) (arr <- 1:81) length(arr) class(arr) Mat <- matrix(mat, ncol=2) # dim(mat) <- c(2,2) Mat (Arr <- array(arr, dim=c(9,3,3))) # zweidimensionale Darstellung nur möglich: (Arr <- array(arr,dim=c(3,3,3,3))) Arr[1,1,1, , drop = FALSE] Arr[2,1,1,1] class(Arr) ### Arrays als "Sammlung von Matrizen" Arr[ , ,1,1] Arr[,,1,1] %*% Arr[,,2,1] ### Gleiche atomare Datentypen erzwungen (wie in Vektor und Matrix!) Arr[1,1,1,1] <- "abc" class(Arr) class(Arr[1,1,1,2]) # "Reduktion" des Arrays auf einen reinen "character" Array mat dimnames(mat) <- list(c("r1", "r2"), c("s1", "s2")) ### Benennung der Dimensionen dimnames(Arr) dimnames(Arr) <- list( c("a1","a2","a3") , c("b1","b2","b3") , c("c1","c2","c3") , c("d1","d2","d3") ) Arr Arr["a1", "b2", "c3", "d1"] # 1. Zeile, 2. Spalte, 3. Tiefe, 1. Dimension ################################################# ### Datenstrukturen 4: Listen (= Ansammlung von Objekten verschiedener Strukturen/Typen) ################################################# ### Die Liste, flexibelstes Datenobjekt in R, enthält unterschiedlichste Datenstrukturen # Zur Erinnerung vector <- c(a = 1, b = 2, c= 3) L1 <- list( a = 1:3, A = matrix(1:9,3,3), w = "Hallo!" # Elemente können Namen haben UND beliebiger Art sein! ) L1 # Ansprechen der einzelnen Listeneinträge # 1. Mit "$" mat <- L1$A # Ansprechen der Elemente geht über Listenname$Elementname .... # 2. Mit der Listenposition/Elementnummer L1[[3]] # ... oder mit Listenname[[Elementnummer]]... L1[2:3] # 3. Mit Name (in Hochkommata) und doppeltem eckigen Klammern L1[["A"]] # Analog zu Vektoren können Listen auch mit Listen erweitert werden (a <- 1:10) c(a, a-1) L2 <- list( L1 = L1, ARR= array(0,c(10,10,2))) # ... so kann auch eine Liste Teil einer Liste sein! L2 $ARR L1$neu <- list(ff = 1:10, olsCoef) str(L2) # Ãœberblick über die Struktur (sehr wichtig !!!) str(L2 , max = 1) str(lm1 , max=1) ### Aufgabe B6 # Erzeugen Sie selbst eine Liste mit drei verschiedenen Datentypen und Namen. # Benutzen Sie selbst eine numerische Indizierung und eine Indizierung per Namen. # Benutzen Sie außerdem den structure Befehl. # Machen Sie nun eine Liste von Listen von Listen. ### Ãœbergang zwischen den Klassen class(paste("Die Zahl ist", 5, sep=" ")) ?as.numeric() # z.B. "5" wird 5 a <- "5" class(a) b <- as.numeric(a) class(b) a = as.numeric("5") a = as.numeric("abc") a = as.numeric("234") a = as.numeric("c(2,3,4)") a = as.numeric(c("2","3","4")) a = as.numeric("TRUE") class(a) as.character() # z.B. 5 wird "5" ?as.character # genauso: as.logical(), as.integer() c() # macht aus Matrix einen Vektor; aus einem Array einen Vektor matrix() # macht aus Vektor eine Matrix array() # macht aus Vektor ein Array unlist() # macht aus Liste einen Vektor class(unlist(L1)) # Charakter die schwächste Klasse; Reduktion deswegen auf Character ch <- "5" ch + 12 as.numeric(ch)+12 ### Aufgabe B7 # Wandeln Sie die folgenden Objekte einzeln in so viele Objektklassen wie möglich um! # Erzeugen Sie eine Liste aus allen 4 Elementen, sprechen Sie alles einzeln an, geben Sie # Einzelnamen an. TRUE 33.5 "Hello" NA ### Aufgabe B8 # Ãœberlegen Sie sich eine erste "code convention", d. h. eine einheitliche Bezeichnungskonvention # für Zahlen, Vektoren, usw. für einen leserlichen Programmierstil, d. h. legen Sie für Sich selbst # fest, wie Sie Funktionen, Zahlen, Matrizen, Listen und Co unterscheiden wollen. # Lesen Sie sich dazu den zugehörigen Wikipedia Artikel oder Google's R Style Guide (s. Homepage) durch. ################################################# ### Datenstrukturen 5: factors , Datum/Zeit, Zeitreihenobjekte ################################################# ### Faktoren (Kategoriale Daten) # ist kein atomarer Datentyp mehr; Unterschied ist, # dass R intern einen Wert vergibt, # nach aussen aber ein Name dargestellt wird # vgl. Dummy-Variablen in großen Datensätzen (geschlecht <- rep(c(1,2), each = 5)) class(geschlecht) (factor.geschlecht <- factor(geschlecht, labels=c("weiblich", "männlich"))) class(factor.geschlecht) # Umwandlung eines numerischen Werts in ein Objekt vom Typ factor str(factor.geschlecht) # STRucture des Faktors bzw. interne Werte factor.geschlecht <- factor(factor.geschlecht, levels=c("männlich", "weiblich")) factor.geschlecht # Reihenfolge vertauscht str(factor.geschlecht) # character-Vektor mit 3 möglichen Ausprägungen (Z <- c("Ja","Ja","Nein","Ja","Vielleicht","Nein","Vielleicht","Ja","Ja","Nein")) class(Z) # Besser als factor-Objekt (ZF <- factor(Z)) class(ZF) # # Vorteile: # + effizienter zu speichern # + schöner # + in Plots und Regressionen verwendbar (vgl. coplots später) summary(Z) summary(ZF) # Beispiel für Objektorientierung in R (siehe oben!) levels(ZF) # Alle Ausprägungen # Geordnete Kategorien -> Reihenfolge der levels interpretierbar # O <- c("sehr gut","mittel","gut","schlecht","gut","schlecht","mittel","sehr gut","gut") ?ordered class(O) OF <- ordered( O , levels=c("sehr schlecht","schlecht","mittel","gut","sehr gut")) OF # Hinzufügen einer Ordnung class(OF) ### Aufgabe B9 # Erzeugen Sie einen Faktor mit den Ausprägungen "Hessen", "Bayern", # "Baden Württemberg" und "Thüringen". # Ordnen Sie ihn alphabetisch an. ################################################# ### Datums- und Zeitangaben (Jetzt <- Sys.time()) # amerikanisches Ausgabeformat mit Ãœbernahme der Zeitzone # wichtig in jeder Sprache: Wie ist das Datumsformat?!!? class(Jetzt) timestamp <- as.numeric(Jetzt) # numerische Ausgabe der Sekunden seit 1.1.1970 timestamp timestamp/60/60/24/365.25 # von Sekunden auf Minuten, Stunden, Tage, Jahre ### 1. Möglichkeit: Datumsangaben als Zeichenfolgen # Probleme bei Programmierung: Zeitumstellungen, Schaltjahre, Feiertage, ... char <- "1992-02-10" class(char) as.numeric(as.Date("1992-02-10")) class(as.Date("1992-02-10")) class(c("1979-09-14","1987-06-09","1989-09-13","1985-07-10")) (GebDat <- as.Date(c("1979-09-14","1987-06-09","1989-09-13","1985-07-10"))) class(GebDat) GebDat[1] - GebDat[2] # aber nicht: (GebDat <- as.Date(c("27.04.2013","15.06.1986"))) # kein eindeutiges Standardformat!!! #Standformat: YYYY-mm-dd # man kann beliebige Formate an as.Date übergeben ?as.Date (GebDat <- as.Date(c("27.04.2013","15.06.1986"), format="%d.%m.%Y")) class(GebDat) testDate<-as.Date(GebDat, format="%d-%m-%Y") testDate GebDat Sys.Date() Sys.Date() - GebDat # Alter in Tagen ... start_date <- as.Date("2010-12-31") end_date <- as.Date("2015-10-06") start_date - end_date thisyear <- seq( from = start_date, to = end_date, by="day") year_wo_sa <- thisyear[ format(thisyear, "%a") != "Sa"] year_wo_saso <- year_wo_sa[format(year_wo_sa, "%a") != "So" ] # Alternativ auf einmal: year_wo_sa <- thisyear[ (format(thisyear, "%a") != "Sa" & format(thisyear, "%a") != "So")] (num_thisyear <- as.numeric(thisyear)) as.numeric(as.Date("2010-01-01")) # R erkennt dass man auf der Tagesebene arbeitet!!! 14610/365.25 # Anzahl der Tage seit 1.1.1970 ### Mit Timestamps (=Anzahl der Sekunden vom 1.1.1970) arbeiten Sys.time() (timestamp <- as.numeric(Sys.time())) (date <- as.POSIXct(timestamp, origin="1970-01-01")) # Umwandlung des Timestamps in ein Datumsformat date <- as.Date("1990-07-17") date format(date, "%Y-%b-%A") format(date, "%m") ################################################# ### Formatierungsmöglichkeiten von Daten: # vgl. # 1. https://www.r-bloggers.com/date-formats-in-r/ # 2. https://www.stat.berkeley.edu/classes/s133/dates.html #%a #Abbreviated weekday name in the current locale. (Also matches full name on input.) #%A #Full weekday name in the current locale. (Also matches abbreviated name on input.) #%b #Abbreviated month name in the current locale. (Also matches full name on input.) #%B #Full month name in the current locale. (Also matches abbreviated name on input.) #%c #Date and time. Locale-specific on output, "%a %b %e %H:%M:%S %Y" on input. #%d #Day of the month as decimal number (01-31). #%H #Hours as decimal number (00-23). As a special exception times such as 24:00:00 are accepted for input, since ISO 8601 allows these. #%I #Hours as decimal number (01-12). #%j #Day of year as decimal number (001-366). #%m #Month as decimal number (01-12). #%M #Minute as decimal number (00-59). #%p #AM/PM indicator in the locale. Used in conjunction with %I and not with %H. An empty string in some locales. #%S #Second as decimal number (00-61), allowing for up to two leap-seconds (but POSIX-compliant implementations will ignore leap seconds). #%U #Week of the year as decimal number (00-53) using Sunday as the first day 1 of the week (and typically with the first Sunday of the year as day 1 of week 1). The US convention. #%w #Weekday as decimal number (0-6, Sunday is 0). #%W #Week of the year as decimal number (00-53) using Monday as the first day of week (and typically with the first Monday of the year as day 1 of week 1). The UK convention. #%x #Date. Locale-specific on output, "%y/%m/%d" on input. #%X #Time. Locale-specific on output, "%H:%M:%S" on input. #%y #Year without century (00-99). On input, values 00 to 68 are prefixed by 20 and 69 to 99 by 19 - that is the behaviour specified by the 2004 and 2008 POSIX standards, but they do also say 'it is expected that in a future version the default century inferred from a 2-digit year will change'. #%Y #Year with century. Note that whereas there was no zero in the original Gregorian calendar, ISO 8601:2004 defines it to be valid (interpreted as 1BC): see http://en.wikipedia.org/wiki/0_(year). Note that the standard also says that years before 1582 in its calendar should only be used with agreement of the parties involved. #%z #Signed offset in hours and minutes from UTC, so -0800 is 8 hours behind UTC. #%Z #(output only.) Time zone as a character string (empty if not available). Where leading zeros are shown they will be used on output but are optional on input. #%C #Century (00-99): the integer part of the year divided by 100. #%D #Date format such as %m/%d/%y: ISO C99 says it should be that exact format. #%e #Day of the month as decimal number (1-31), with a leading space for a single-digit number. #%F #Equivalent to %Y-%m-%d (the ISO 8601 date format). #%g #The last two digits of the week-based year (see %V). (Accepted but ignored on input.) #%G #The week-based year (see %V) as a decimal number. (Accepted but ignored on input.) #%h #Equivalent to %b. #%k #The 24-hour clock time with single digits preceded by a blank. #%l #The 12-hour clock time with single digits preceded by a blank. #%n #Newline on output, arbitrary whitespace on input. #%r #The 12-hour clock time (using the locale's AM or PM). #%R #Equivalent to %H:%M #%t #Tab on output, arbitrary whitespace on input. #%T #Equivalent to %H:%M:%S. #%u #Weekday as a decimal number (1-7, Monday is 1). #%V #Week of the year as decimal number (00-53) as defined in ISO 8601. If the week (starting on Monday) containing 1 January has four or more days in the new year, then it is considered week 1. Otherwise, it is the last week of the previous year, and the next week is week 1. (Accepted but ignored on input.) ################################################# ### Aufgabe B10 # Heute ist der 08.10.2018. Lesen Sie dieses Datum ein # und formatieren Sie es in R (!) als: # a) "20181009" # b) "2018-Oct" # c) "KW: 41" paste("KW: ", format( date , "%W")) ### Aufgabe B11 # Am 27.10.2013 war eine Zeitumstellung von Sommerzeit auf Winterzeit. Versuchen Sie diese Stunde in R # zu reproduzieren. # # 1. Hinweis: Sie können die Funktion as.POSIXct() benutzen. # 2. Hinweis: Es reicht zu zeigen, dass dieser Tag 25 Stunden hatte. ### Zeitreihen (ts - Time Series) = Objekte (für Monats-, Quartals- oder Jahresdaten) # Benötigen das Zeitreihenpaket ?ts() # Time Series objects # als Alternative: zoo Objekt (im Paket zoo) # Arbeitslosenzahlen in Deutschland, beginnend bei Januar 2007 # Quelle: Bundesbank ald <- ts( data = c( 4284691,4247561,4124836,3976555, 3812335,3687597,3715509,3705949, 3543866,3434067,3378747,3406389, 3659316,3617418,3507383,3413881, 3283234,3159769,3209987,3195681, 3080837,2996892,2988425,3102066, 3488801,3551911,3585784,3584798, 3458104,3410036,3462446,3471513, 3346459,3228625,3215393,3275526, 3617485,3643381,3567944,3406344, 3241529,3153300,3191800,3188122, 3031354), start = c(2007,1), frequency = 12) # Start im Jahr 2007 und 1. Zeitabschnitt, # welcher erst durch die Frequenz als Monat identifiziert wird ald # Ausgabe speziell formatiert class(ald) str(ald) tsp(ald) # Time Series Properties - Zeitreiheneigenschaften (Start, Ende, Frequenz) ?window ald2010 <- window( ald , start=c(2010,1) , end=c(2010,9) ) # Teilintervall wählen ald2010 ### Unregelmäßige, tägliche etc. Zeitreihen: Pakete zoo, tseries, timeSeries ... ### Aufgabe B12 # a) Erstellen Sie mit Hilfe des Befehls abs(rnorm(14, sd=0.5)) 14 normalverteilte Zahlen # mit Standardabweichung 0.5 im Betrag. Nehmen Sie an, dass diese Zahlen die jährlichen # bzw. Quartals- bzw. monatlichen bzw. wöchentlichen bzw. täglichen Arbeitslosenzahlen ab # diesem Jahr bzw diesem Quartal bzw diesem Monat bzw dieser Woche bzw. diesem Tag darstellen. # Lesen Sie diese Zahlen mit dem ts() Befehl entsprechend ein. # # ?abs() # Absolutbetrag ?rnorm() # Funktion für Zufallszahlen der Normalverteilung mit (a <- abs(rnorm(n=14, sd=0.5))) # b) Versuchen Sie, monatliche deutsche Daten zur Arbeitslosenquote # und Inflationsrate von 2012 bis 2013 # MANUELL als Vektoren in R zu erzeugen. # Erstellen Sie daraus eine multivariate Zeitreihe # mit Namen 'ts_inf_ur' vom Typ "ts". # Wenden Sie den plot()-Befehl darauf an. # (vgl. https://www.destatis.de) ################################################# ### Datenstrukturen 6: Datensätze (data.frame) ################################################# # Vektoren GLEICHER LÄNGE als Liste zusammengefasst, # Beobachtungen=Zeilen von Variablen=Spalten # Zum Beispiel: FC Bayern Stürmer als Datensatz: Sturm <- data.frame( Vorname = c("Patrick","Mario","Claudio","Mario"), Nachname = c("Weihrauch","Mandzukic","Pizarro","Gomez"), Rückennummer = c(20,9,14,33), ToreBL = c(0,6,0,0), GebDat = as.Date(c("1994-03-03","1986-05-21","1978-10-03","1985-07-10")), stringsAsFactors = FALSE # Namen sollen hier als "character" eingelesen und nicht als "factor" ) Sturm names(Sturm) # Variablennamen Sturm Sturm$ToreBL # Indizierung wie bei Liste ($), auch wie bei Matrix ([,]) möglich Sturm[ ,3] # Numerische Indizierung wie bei Matrix Sturm[ ,"ToreBL"] # Namentliche Indizierung Sturm[Sturm$Nachname=="Gomez" , ] # logische Indizierung Sturm[Sturm$Vorname=="Mario" , ] # logische Indizierung # Weitere Variable Hinzufügen via "$" Sturm$EinsätzeBL <- c(0,5,7,0) Sturm # Weiter Variable hinzufügen via cbind cbind( Nachname=Sturm$Nachname, Torquote=Sturm$ToreBL/Sturm$EinsätzeBL ) # Berechnungen # Als Liste hinzufügen Sturm[5,] <- list("Thomas", "Müller", 25, 4, as.Date("1989-09-13"), 6) # Weitere Beobachtung Sturm summary(Sturm) # Gängige arithmetische Operationen anwendbar sum( Sturm$ToreBL ) mean( Sturm$ToreBL ) # Einzelne Variablen im "Suchpfad" verfügbar machen Sturm$ToreBL ToreBL # Variable existiert nicht attach(Sturm) ToreBL # Nun sind die Vektoren Verfügbar OHNE Sturm$... davorschreiben zu müssen detach(Sturm) ToreBL # Jetzt ist sie wieder weg attach(Sturm) # !VORSICHT!: Am Datensatz selbst wird hier nichts verändert!!! ToreBL[1] <- 13 # Also: attach() nur zum Lesen und Verwenden der Daten, nicht zum Verändern verwenden ToreBL Sturm detach(Sturm) Sturm # Also: Sollen die Daten geändert werden: Datensatz selbst ansprechen! Sturm$Vorname[3] <- "Pizza" Sturm ## Weitere Datensatzfunktionen # Teilmenge von Beobachtungen (subset) und Variablen (select) ?subset subset( Sturm , subset = ToreBL>1, # Beobachtungen/Zeilen select= c(Rückennummer,Nachname) )# Spalten # Auch mehrere logische Ausdrücke möglich: subset( Sturm , subset = ToreBL>1 & Rückennummer < 15, # Beobachtungen/Zeilen select= c(Rückennummer,Nachname) )# Spalten # Zusammenfassung summary(Sturm) # Die ersten Beobachtungen head(Sturm) # Die letzten Beobachtungen tail(Sturm) ### Aufgabe B13 # Benutzen sie den gerade erstellten data.frame "Sturm" und machen Sie folgendes: # a) Ändern Sie den Spaltennamen "Vorname" in "prename". # b) Sprechen Sie die Bundesligatore auf zwei verschiedene Arten an (vgl. data.frame-Matrix-Listen-Ähnlihckeit). # c) Geben Sie sich eine logischen Indizierung aller Spieler aus, die mehr als 1 Tor schossen. # d) Fügen Sie eine neue Beobachtung(Zeile) (z. B. Sie selbst) mit willkürlichen Daten hinzu. # e) Fügen Sie eine neue Eigenschaft(Spalte) der Spieler hinzu. # f) Wählen Sie alle Spieler mit mehr als einem Tor und Geburt nach 1987 aus. ################################################# ### Datensätze erfassen, einlesen und ausgeben ################################################# #setwd("G:/PMR/data") getwd() # Wir wollen den Datensatz "Afrika.xls" einlesen; # Durch Öffnen mit Excel sieht man, dass ein teilweiser Kopf vorhanden ist, # das Tausendertrennzeichen das Leerzeichen " " und das Dezimaltrennzeichen das Komma "," ist. # Da wir ein gängiges Format möchten, markieren wir die Zahlen und stellen das Zahlenformat ohne Tausendertrennzeichen ein. # Danach speichern wir die Datei im csv-Format als Afrika.csv ?read.csv africaRaw <- read.csv(file = "data/Africa.csv", header = FALSE,# kein Header vorhanden sep=";", # Spaltentrennzeichen = ";" dec=",", # Dezimaltrennzeichen = "," na.strings = "", stringsAsFactors = FALSE) # Strings als Namen einlesen? ## Falls Konvertierung in Excel nach csv nicht klappt: africaRaw <- read.csv(file = "http://pc1011601230.ur.de/Africa.csv", header = FALSE,# kein Header vorhanden sep=";", # Spaltentrennzeichen = ";" dec=",", # Dezimaltrennzeichen = "," na.strings = "", stringsAsFactors = FALSE) # Strings als Namen einlesen? africaSel <- subset(africaRaw,select = 2:8) # nur spalte 2:8 behalten, die anderen sind leer africa <- na.omit(africaSel) # Kommentar: # Spalten benennen, Einheiten notieren, ... names(africa) colnames(africa) <- c("Land", "Bevölkerung", "Landesgröße", "Bevölkerungsdichte", "GDP", "GDP/Capital", "Wachstum") # ...oder so ähnlich ### Daten einlesen # Aus "Standard" Tabellen (*.txt, *.csv, *.asc) # csv = comma seperated value # asc = american standard code # ascii = american standard code for information interchange ?read.table # Ãœbersicht: ######################################################## # Funktion header sep dec ######################################################## # read.table() FALSE " " "." # read.csv() TRUE "," "." # read.csv2() TRUE ";" "," # read.delim() TRUE "\t" "." # read.delim2() TRUE "\t" "," # # analog (write.table(), write.csv(), ... ) zum Erstellen: Sturm write.table(Sturm, file="data/Sturm_1.txt") write.table(Sturm, file="data/Sturm_2.txt", sep="()()()") # Wissenschaftlicher Standard: write.table(Sturm, file="data/Sturm_3.csv", sep=";", dec = ".") # Vorher aber wichtig: # Wie findet man heraus, welche Struktur Textsätze haben? # Exkurs Notepad++ (schnelle Verändung von Datensätzen) # Beispieldatei: Africa.xls - Wie kann man die Struktur einlesbar machen? # - Öffnen einer xls Datei mit Hilfe von Notepad++ liefert wirres Zeug -> Aushilfe: als .csv Speichern # - Struktur erkennbar: Dezimaltrennzeichen "."; Spaltentrennzeichen ";"; Zeilentrennzeichen "\n". # Erklärung wichtiger Escape-Symbole finden Sie hier: https://de.wikipedia.org/wiki/Escape-Sequenz # lieft Ãœberblick über Escape-Sequenzen # Änderung von Dezimaltrennzeichen "." auf ",": Notepad++ -> STRG+F -> Ersetzen . durch , -> Alles ersetzen # Änderung des Zeilentrennzeichens: analoge Prozedur: \n durch -- ### Aufgabe B14 (Notepadd++ mit STRG+F) # Laden Sie auf www.regelleistung.net unter "Ãœbersicht/Ergebnisse" als # Produktart die Minutenreserveleistung vom 06.10.2015 als Datei herunter (blauer Button). # Öffnen Sie die Datei mit Notepad++ und ändern Sie folgende Sachen: # - Dezimaltrennzeichen soll der Punkt sein. # - Statt "11.10 - 11.10.2016" soll nur noch "11.10.2015" stehen. (STRG+Z macht Ihre letzte Aktion rückgängig) # - Spaltentrennzeichen soll der Tabulator "\t", denken Sie dabei, dass Sie regular expressions inkludieren. ?read.table() test <- read.table(file = "data/ERGEBNISLISTE_ANONYM_MRL_2016-10-11.CSV", header = TRUE,# kein Header vorhanden sep="\t", # Spaltentrennzeichen = ";" dec=".", # Dezimaltrennzeichen = "." na.strings = " ", row.names=NULL, stringsAsFactors = FALSE) # Strings als Namen einlesen? summary(test) ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### Aufgabe B15 # Lesen Sie die aktuellen Arbeitslosenzahlen in Deutschland # (Anzahl, Quote) auf Kreisebene in R ein. Hinweise: # http://statistik.arbeitsagentur.de/Navigation/Statistik/Statistik-nach-Themen/Arbeitslose-und-gemeldetes-Stellenangebot/Arbeitslose/Arbeitslose-Nav.html # -> Ãœbersicht für Kreise und kreisfreie Städte (Monatszahlen) # Alternative: Homepage: ALQ_Kreisebene! # Wandeln Sie den relevanten Teil der xls-Tabelle in ein Komma- oder Tab-Getrenntes Format um. # Verwenden Sie den Befehl read.table und lesen Sie den Datensatz als data_arge ein. # Nach Einlesen machen Sie folgendes: # a) Summary ausgeben lassen (Ãœberprüfen, ob alle Variablen passen) # b) Falls Sie die Ãœberschriften nicht eingelesen haben, übergeben Sie dem Datensatz nun folgende Ãœberschriften: # c) Machen Sie den Datensatz verfügbar, indem Sie die Spalten einzeln ansprechbar machen. # d) Nutzen Sie die Teilmenge des Datensatzes, die nur noch Kreis, Abs_tot, Quote_tot beinhaltet. # e) Berechnen Sie von dieser Teilmenge ausgehend die gesamte Erwerbsbevölkerung und die gesamte # Arbeitslosenquote # f) Trunkiert man den Kreisschlüssel, nachdem man ihn durch 1000 teilt, so gehört # jede Zahl 1 bis 16 zu einem Bundesland. # Die Reihlenfolge ist dabei: # "Schleswig-Holstein","Hamburg","Niedersachsen","Bremen","NRW","Hessen","Rheinland-Pfalz","BW","Bayern","Saarland", # "Berlin","Brandenburg","Mecklenburg-Vopo","Sachsen","Sachsen-Anhalt","Thüringen" # Fügen Sie nun eine neue Spalte ein, die zu jeder Beobachtung angibt, in welchem Bundesland sie ist. # Hinweis: Sie könnten die Funktion trunc() gebrauchen. # g) Benutzen Sie nun den order() Befehl und geben Sie sich die Kreise mit den 30 höchsten # Arbeitslosenquoten aus. # h) Speichern Sie nun den Datensatz als ALQ_Kreise.txt ab und den (kompletten) data.frame inklusive # der Bundesländer als alq.RData. # (Letzter samt der Bundesländer wird später noch benötigt)