2 Rechenoperationen und Programmablauf in R in:

Andreas Behr, Ulrich Pötter

Einführung in die Statistik mit R, page 24 - 41

2. Edition 2010, ISBN print: 978-3-8006-3599-3, ISBN online: 978-3-8006-4878-8, https://doi.org/10.15358/9783800648788_24

Series: Vahlens Kurzlehrbücher

Bibliographic information
R P R Dieses Kapitel gibt einen Überblick über die wichtigsten numerischen Funktionen. R benutzt vektorisierte Funktionen, die auf allen Elementen eines Vektors operieren. Diese Konstruktion erlaubt eine sehr durchsichtige und kompakte Schreibweise für alle wichtigen Operationen, die sich auf Datensätze beziehen. Außerdem werden die wichtigsten Elemente für die Ablaufsteuerung vorgestellt. Ein wesentlicher Aspekt ist die Möglichkeit, die herkömmlichen Schleifen über alle Beobachtungen durch Konzepte zu ersetzen, die Anweisungen für durch passende Bedingungen definierte Teilmengen der Daten durchführen. Diese Konzepte (und deren Realisation in R) können viele Berechnungen erheblich beschleunigen. Die systematische Verwendung dieser Programmelemente erhöht zudem die Lesbarkeit der Programme. 2.1 Operatoren und mathematische Funktionen 2.1.1 Logische Operatoren 2.1.2 Mathematische Funktionen 2.1.3 Mengenoperationen 2.1.4 Vektorisierte Funktionen 2.1.5 Spezielle Vektorfunktionen 2.1.6 Matrixoperationen 2.1.7 Rechengenauigkeit und Rundungsfehler 2.1.8 Operationen mit Texten 2.1.9 Sequenzen und Wiederholungen 2.2 Programmablauf 2.2.1 Funktionen 2.2.2 Schleifen 2.2.3 Vermeidung von Schleifen 2.2.4 Bedingte Anweisungen 2.3 Übungsaufgaben Rechenoperationen und Programmablauf in R . Operatoren und mathematische Funktionen . . Logische Operatoren Logische Ausdrücke sind Ausdrücke, die logische Variable durch ! (logische Negation), & (logisches Und) und | (logisches Oder) kombinieren. Logische Variable entstehen u.a. durch Vergleiche: > 5 < 7 [1] TRUE > 5 == 7 [1] FALSE Vergleichsoperatoren sind neben == (logische Gleichheit, zwei Gleichheitszeichen nacheinander) und < (kleiner als) die Vergleichsoperatoren >, <=, >= und != (logische Ungleichheit). Logische Variable können auch denWertNA haben. DerWertNA ergibt sich, wenn der Wahrheitswert nicht eindeutig entschieden werden kann. Insbesondere ist NA & TRUE NA, dagegen ist NA | TRUE TRUE, weil der Ausdruck unabhängig vomWahrheitswert der fehlenden Angabe wahr ist. Logische Ausdrücke können insbesondere als Indizes und zur Auswahl von Fällen benutzt werden. Betrachten wir noch einmal den Datensatz dat1 des letzten Kapitels: > Name < c("A","B","C") > Alter < c(22,35,41) > Geschlecht < as.logical(c(0,1,0)) > dat1 < data.frame(x,Alter,Geschlecht) > attach(dat1) > Alter[Alter>30] [1] 35 41 > Alter[Geschlecht==TRUE] [1] 35 Die logischen Werte TRUE und FALSE können durch T und F abgekürzt werden. Achtung: Diese Abkürzungen können durch entsprechende Definitionen von F oder T überschrieben werden! Etwa: > Alter[Geschlecht==T] [1] 35 > T < c(3,6,4) > T [1] 3 6 4 > Alter[Geschlecht==T] [1] numeric(0) Entweder man vermeidet es, T und F als Variablennamen zu verwenden oder man schreibt die Wahrheitswerte immer als TRUE bzw. FALSE. . Operatoren und mathematische Funktionen Werden logische Variable etwa mit as.numeric() zu numerischen Variablen verwandelt, dann wird aus TRUE und aus FALSE . . . Arithmetische Operatoren und mathematische Funktionen R stellt die üblichen binären arithmetischen Operatoren +, , ∗, / sowie ^ (Exponentiation), %% (Modulo) und %/% (ganzzahliges Teilen) zur Verfügung. Die Ergebnisse der entsprechenden Operatoren können wieder reelle oder ganze Zahlen oder NA für fehlende Angaben sein. Auch die Werte Inf (positiv unendlich) und Inf (negativ unendlich) sind zulässig. Kann kein gültiger Wert berechnet werden, dann wird NaN (Not a Number) zurückgegeben. > 2∗2 [1] 4 > 2∗NA [1] NA > 2/0 [1] Inf > 2/0 [1] Inf > 0/0 [1] NaN Neben den einfachen binären Operatoren stellt R eine Reihe von Funktionen bereit. Im Folgenden sind einige wichtige mathematische Funktionen aufgeführt; Funktionen, die hauptsächlich in der Statistik verwandt werden, finden sich in den folgenden Kapiteln. abs(),sign() Betragsfunktion und Vorzeichen round(),ceiling(),Ćoor(),trunc() Rundung und Abschneiden sqrt() Quadratwurzel exp() Exponentialfunktion log10() Logarithmus zur Basis log() Natürlicher Logarithmus sin(),cos(),tan() Sinus, Cosinus, Tangens asin(),acos(),atan() Arcussinus etc. sinh(),cosh(),tanh() Hyperbolischer Sinus etc. asinh(),acosh(),atanh() Hyperbolischer Arcussinus etc. gamma() Gamma-Funktion lgamma() Logarithmus der Gamma-Funktion digamma() Ableitung der Log-Gamma-Funktion trigamma() . Ableitung beta(a,b) Beta-Funktion Γ(a)Γ(b)/Γ(a + b) lbeta() Logarithmus der Beta-Funktion Die Argumente der Winkelfunktionen werden in Radians, nicht in Winkelgraden angegeben. Rechenoperationen und Programmablauf in R Zusätzlich kann die Fakultät n! durch factorial(n) (bzw. deren Logarithmus durch lfactorial(n)) berechnet werden. Die Binomialkoeffizienten nk := n!/(k!(n k)!) können durch choose(n,k) berechnet werden. Einige der Funktionen, insbesondere die Wurzelfunktion sowie die Exponentialfunktion und der Logarithmus, erlauben komplexe Argumente: > sqrt( 2) [1] NaN Warnmeldung: In sqrt( 2) : NaNs wurden erzeugt > sqrt( 2 + 0i) [1] 0+1.414214i > log( 1.5) [1] NaN Warnmeldung: In log( 1.5) : NaNs wurden erzeugt > log( 1.5+0i) [1] 0.405465+3.141593i . . Mengenoperationen Die Elemente eines Vektors können wie Mengen behandelt werden, zumindest, wenn sie keine mehrfachen Werte enthalten. Die Funktion unique() entfernt aus einem Vektor alle mehrfachen Werte. Angewandt auf einen Dataframe werden mehrfach vorkommende Zeilen des Dataframes entfernt. duplicated() gibt einen logischen Vektor der gleichen Länge wie das Argument zurück, der den Wert TRUE an den Stellen hat, an denen sich ein Wert wiederholt. > a < c(1,2,3,2,4,2,1) > unique(a) [1] 1 2 3 4 > duplicated(a) [1] FALSE FALSE FALSE TRUE FALSE TRUE TRUE Ob zwei Vektoren als Mengen gleich sind, kann mit der Funktion setequal() getestet werden, ob ein Vektor bestimmte Elemente enthält, wird durch is.element() getestet. union() und intersect() geben die Vereinigungsmenge bzw. den Durchschnitt zweier Vektoren wieder (mehrfach auftretende Werte werden ausgeschlossen). setdif(x,y) berechnet die mengentheoretische Differenz x y. > a < c(1,2,3,2,4,2,1) > b < c(1,3,1) > union(a,b) Ein Ausdruck der Form „a := b“ besagt, dass der Ausdruck auf der linken Seite durch den Ausdruck auf der rechten Seite definiert wird. Ähnlich benutzen wir „=:“. . Operatoren und mathematische Funktionen [1] 1 2 3 4 > intersect(a,b) [1] 1 3 > setdif(a,b) [1] 2 4 > is.element(b,a) [1] TRUE TRUE TRUE is.element() kann durch %in% abgekürzt werden: > b %in% a [1] TRUE TRUE TRUE . . Vektorisierte Funktionen Nicht nur die Mengenfunktionen, sondern alle bisher vorgestellten Funktionen und Operatoren können auf Vektoren angewandt werden. Sie berechnen dann die entsprechende Funktion für jedes Element des Vektors. Die binären Operatoren +, ,∗,/,%%,%/% können auf zwei Vektoren angewandt werden. Haben beide die gleiche Länge, werden die jeweiligen Elemente an den gleichen Positionen verknüpft. Haben die Vektoren unterschiedliche Längen, dann wird der kürzere solange wiederholt, bis die Länge des längeren erreicht ist. Das erlaubt sehr komprimierte Berechnungen, kann aber auch leicht zu Fehlern führen. Deshalb wird eine Warnung ausgegeben, wenn die Länge des längeren Vektors nicht ein Vielfaches der Länge des kürzeren Vektors ist. > a < c(1,0.222, 3,23) > a^2 [1] 1.000000 0.049284 9.000000 529.000000 > sin(a) [1] 0.8414710 0.2201810 0.1411200 0.8462204 > a+1 [1] 2.000 1.222 2.000 24.000 > b < c(1,2) > a+b [1] 2.000 2.222 2.000 25.000 > a+c(1,2,3) [1] 2.000 2.222 0.000 24.000 Warnmeldung: In a+c(1,2,3): Länge des längerenObjektes ist kein Vielfaches der Länge des kürzeren Objektes Das Auffüllen des kürzeren Vektors nach dieser Regel wird „recycling rule“ genannt. Rechenoperationen und Programmablauf in R . . Spezielle Vektorfunktionen Die Funktion sum() berechnet die Summe, die Funktion prod() das Produkt der Elemente des Arguments. Die Befehle min() bzw. max liefern die Minima und Maxima ihrer Argumente. Entsprechend können die Funktionen which.min() bzw. which.max() dazu benutzt werden, die Position eines Minimums oder Maximums in einem Vektor zu bestimmen. Der Befehl cumsum() erzeugt einen Vektor gleicher Länge wie der übergebene Vektor, der an jedem Eintrag die kumulierte Summe bis zu dem entsprechenden Vektoreintrag enthält. Als erster Eintrag erscheint also x[1], als zweiter Eintrag x[1]+x[2] usw.: > x < c(3,1,2,5,4) > cumsum(x) [1] 3 4 6 11 15 Der Befehl cumprod() funktioniert ganz analog, nur dass anstelle der Summe jeweils das Produkt gebildet wird. Als erster Eintrag erscheint daher x[1], als zweiter Eintrag x[1]∗x[2] usw.: > cumprod(x) [1] 3 3 6 30 120 . . Matrixoperationen Matrizen können durch den matrix() Befehl erzeugt werden. > A < matrix(c(1,2,3, + 0,1,2, + 1,0,4, + 0,0,1),nrow=4,ncol=3,byrow=TRUE) > A [,1] [,2] [,3] [1,] 1 2 3 [2,] 0 1 2 [3,] 1 0 4 [4,] 0 0 1 > dim(A) [1] 4 3 > nrow(A) [1] 4 > ncol(A) [1] 3 Es muss also neben den Elementen der Matrix noch deren Dimension (durch nrow= bzw. ncol=) angegeben werden. byrow=FALSE ist die Voreinstellung, dann werden die Elemente der Matrix spaltenweise aufgefüllt. dim() gibt die Dimension der Matrix an und nrow() bzw. ncol() sind hilfreiche Abkürzungen für dim(A)[1] bzw. dim(A)[2]. . Operatoren und mathematische Funktionen Matrixoperationen sind ein wesentlicher Bestandteil aller statistischen Prozeduren. Wir stellen daher eine vollständigere Liste der in R implementierten Operationen wie Matrixmultiplikationen, Inverse etc. in einem eigenen Abschnitt zusammen (Abschnitt . . ). . . Rechengenauigkeit und Rundungsfehler Wie alle Programme rechnet R mit endlichen Darstellungen von Zahlen. Diese Darstellungen sind in den meisten Fällen nur Näherungen der entsprechenden reellen Zahlen. Da die Darstellung in binärer Form erfolgt, haben nicht einmal die endlichen Dezimalzahlen immer eine exakte Darstellung. Das muss beachtet werden, wenn man etwa nach der Gleichheit von Ergebnissen sucht: > 1 0.8 [1] 0.2 > 1 0.8==0.2 [1] FALSE > a < sqrt(2) > a∗a [1] 2 > a∗a==2 [1] FALSE Eine sichere Möglichkeit, ungefähre Gleichheit zu testen, bietet die Funktion all.equal(). > all.equal(a∗a,2) [1] TRUE > all.equal(1 0.8,0.2) [1] TRUE Allerdings gibt es keine Möglichkeit, Rundungsfehler ganz zu umgehen. Ist man sich dessen nicht bewusst, dann könnte man etwa mit R ein Gegenbeispiel zum berühmten „letzten“ Satz von Fermat konstruieren > all.equal(1782^12+1841^12,1922^12) [1] TRUE Zum Glück hatte Fermat keinen Taschenrechner. Aber auch ohne exakte Arithmetik: Der erste Summand muss gerade sein, der zweite ungerade, die Summe also ungerade. 1922^12 aber ist gerade. Die Anwendung von weiteren Funktionen auf Zwischenergebnisse wird Rundungsfehlermeist vergrößern. Insbesonderewird diemaximaleGenauigkeit von ca. Stellen selten erreicht und die Rechenergebnisse sind nach einigen Zwischenschritten i.d.R. nur noch - Dezimalstellen genau. Zudem kann es bei mehreren Operationen auch zu katastrophalen Fehlern kommen, so dass die Ergebnisse nicht einmal mehr in der Nähe der mathematisch korrekten Lösung liegen. In den Übungen findet sich ein Beispiel. Rechenoperationen und Programmablauf in R . . Operationen mit Texten R verfügt über eine ganze Reihe von Befehlen zur Behandlung von character Vektoren. Hier sei nur auf den paste() Befehl verwiesen, mit dem neue Bezeichnungen erzeugt werden können. Das ist besonders hilfreich bei der automatisierten Konstruktion von Variablennamen und bei der Beschriftung von Graphiken. > paste("V",1:5,sep="") [1] "V1" "V2" "V3" "V4" "V5" Das Argument zur Option sep= ist das Trennzeichen, das zwischen die zu verbindenden Teile eingefügt wird. Die Voreinstellung ist ein Leerzeichen sep=" ". paste() operiert elementweise auf Vektoren und benutzt wie im Beispiel Recycling-Regeln, wenn einer der Vektoren zu kurz ist. Soll auch der Vektor zu einem Gesamtstring verwandelt werden, dann kann man die Option collapse= verwenden. Dann werden die Elemente des erzeugten Vektors aneinandergehängt, wobei die Elemente durch das in der collapse= Option angegebene Zeichen getrennt werden. > paste("V",1:5,sep="",collapse="+") [1] "V1+V2+V3+V4+V5" Mit dieser Option lassen sich auch relativ leicht Formeln manipulieren. . . Sequenzen und Wiederholungen Sequenzen Eine häufig gebrauchte Sequenz ist eine Folge natürlicher Zahlen von a bis b, etwa wenn entsprechende Zeilen oder Spalten aus einer Matrix oder einem Dataframe ausgewählt werden sollen. Diese kann man mit dem Operator a:b erstellen. Die Folge kann dabei ansteigend oder auch abfallend sein. > 1:5 [1] 1 2 3 4 5 > 17:13 [1] 17 16 15 14 13 Der Operator : bindet stärker als die arithmetischen Operatoren +, ,∗,/: > 1:5 + 3 [1] 4 5 6 7 8 > 1:5∗2 [1] 2 4 6 8 10 Aber: > (1:3)^2 [1] 1 4 9 > 1:3^2 [1] 1 2 3 4 5 6 7 8 9 . Operatoren und mathematische Funktionen Die Funktion seq(from=a,to=b,by=c) bietet eine flexiblere Möglichkeit, Sequenzen zu erstellen. Hier kann man den Anfangswert a, den Endwert b und die Schrittlänge c bestimmen: > a < seq(from=0,to=1,by=0.1) > a [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 Achtung: Selbst bei dieser einfachen Sequenz kann es zu unerwarteten Problemen aufgrund der endlichen Rechnergenauigkeit kommen: > 0.1 %in% a [1] TRUE > 0.3 %in% a [1] FALSE Wiederholungen Wenn Objekte (Skalare, Vektoren) mehrmals wiederholt werden sollen, steht hierfür in R die Funktion rep(a,b) (wie „replicate“) zur Verfügung. Das erste Argument a gibt an, welches Objekt wiederholt werden soll, das zweite Argument b, wie oft a wiederholt werden soll. Ein Vektor mit Einsen lässt sich z.B. so erzeugen: > rep(1,10) [1] 1 1 1 1 1 1 1 1 1 1 Analog können auch Vektoren wiederholt werden: > rep(1:4,2) [1] 1 2 3 4 1 2 3 4 Die einzelnen Einträge des zu wiederholendenObjektes können unterschiedlich oft wiederholt werden: > rep(1:4,4:1) [1] 1 1 1 1 2 2 2 3 3 4 Die Funktion rep() kann auch zur Wiederholung von anderen Objekten, etwa von Textobjekten, verwandt werden: > rep(c("Schneewittchen","Zwerg"),c(1,7)) [1] "Schneewittchen" "Zwerg" "Zwerg" "Zwerg" "Zwerg" [6] "Zwerg" "Zwerg" "Zwerg" Der verkürzte Befehl seq(0,1,0.1) führt durch die Berücksichtigung der Reihenfolge der Angaben im Funktionsaufruf zum gleichen Resultat. Die Zahlen in eckigen Klammern zu Beginn der Ausgabezeilen geben an, um das wievielte Element des Vektors es sich bei dem rechts anschließenden Wert handelt. Rechenoperationen und Programmablauf in R . Programmablauf . . Funktionen In R ist es möglich, eigene Funktionen zu definieren. Eine Funktionsdefinition besteht aus drei Teilen: Dem Namen der Funktion, der Angabe ihrer Argumente und im Rumpf der Funktionsdefinition eine Abfolge von Befehlen und Definitionen. Mit nur einem Argument kann man z.B. schreiben: > plus1 < function(x){x+1} > z < 3:5 > plus1(z) [1] 4 5 6 Beim Aufruf der Funktion plus1(z) wird der Funktion plus1 der Wert des Objektes z übergeben. Der Wert des übergebenen Objektes wird also nicht geändert, selbst wenn im Rumpf der Funktion eine entsprechende Zuordnung stattfindet: > plus2 < function(x){x< x+2;x} > x < 1:2 > plus2(x) [1] 3 4 > x [1] 1 2 Objekte, die innerhalb des Rumpfs der Funktion definiert werden, existieren nur in der durch die Funktion definiertenUmgebung.Wenn imRumpf der Funktion auf einen Objektnamen verwiesen wird, dann wird das zugehörige Objekt zunächst in der Funktionsumgebung gesucht. Wird es dort nicht gefunden, dann wird in der Umgebung gesucht, in der die Funktion aufgerufen wurde. > plusa < function(x){x< x+a;x} > a < 1:5 > x < 0:4 > plusa(x) [1] 1 3 5 7 9 Es ist natürlich besser, die Werte, die zur Berechnung im Rumpf der Funktion benutzt werden, auch explizit als Argumente der Funktion anzuführen: > plusa < function(x,a){x< x+a;x} > plusa(x,a) [1] 1 3 5 7 9 Die Definition einer Funktion kann man sich anzeigen lassen, indem man ihren Namen (ohne runde Klammern) angibt. Das gilt auch für viele der von R zur Verfügung gestellten Funktionen. > plusa function(x,a){x< x+a;x} Die Angabe L nach einer Zahl erzeugt eine Zahl vom Typ integer. 1 10 35 83 _W iS o B eh r P öt te r 2A - B g 1 . Programmablauf > nrow function(x) dim(x)[1L] Zu beachten ist, dass ein Symbol sowohl für eine Funktionsdefinition als auch fürWerte stehen kann. Das gilt auch für die von R bereitgestellten Funktionen: > sin < c(5,8) > sin [1] 5 8 > sin(pi/8) [1] 0.3826834 Aber selbst die Redefinition der von R bereitgestellten Funktionen ist möglich. > sin < function(x){x+1} > sin(2) [1] 3 UmmöglicheVerwirrungen zu begrenzen, sind namespaces eingeführt worden. Damit ist ein Zugriff auf die Funktion auch noch nach einer Redefinition möglich. Z.B. ist die Funktion sin (ebenso wie etwa nrow) im namespace des Pakets base definiert. Man kann explizit auf diese Funktion zugreifen, indem der entsprechende namespace verwandt wird: > base::sin(2) [1] 0.9092974 Anfänger werden regelmäßig die sehr kurzen Funktionsnamen c() (Konkatenieren) und t() (Transponierte) als Variablennamen (und manchmal gar als Namen von Funktionen) verwenden. Das ist zwar kein Fehler, kann aber zu ganz überraschenden Folgefehlern und unerwarteten Ergebnissen führen, deren Ursachen nur schwer zu finden sind. . . Schleifen In Programmen können mit einer for-Schleife auf einfache Art Kontrollvariable erzeugt und Befehle wiederholt ausgeführt werden. In einer for-Schleife durchläuft ein zu erzeugender Index einen definierten Wertebereich. Für jeden angenommenenWert wird ein in der for-Schleife angegebener Befehl ausgeführt. Eine for-Schleife besteht aus drei Teilen: Vorangestellt der Befehl for, dann in runden Klammern der Name der Indexvariablen und die Wertemenge, die diese durchlaufen soll. Zuletzt kommt (in geschweiften Klammern) als Rumpf, In R sind symbol und name, also Namen eines Objektes und Symbole für dieses Objekt Synonyme. Man kann einen Charakterwert (einen String) wie „plusa“ durch as.name(’plusa’) in das entsprechende Symbol verwandeln. Das ist nützlich, wenn innerhalb eines Programmes selbst Prorgrammelemente und Funktionen bzw. deren Namen verändert werden sollen. In diesem Zusammenhang sind auch die Befehle assign() und get() hilfreich. Sie weisen Symbolen, die als Charakterstrings gegeben sind, Werte zu bzw. geben die Werte zurück, auf die das Symbol (gegeben als Charakterstring) verweist. 2 10 35 83 _W iS o B eh r P öt te r 2A - B g 2 Rechenoperationen und Programmablauf in R ein Befehl oder ein Block von Befehlen, die bei jedem Schleifendurchlauf abgearbeitet werden. Als Beispiel wählen wir eine Schleife, die durch den Wert x kontrolliert wird, der die Werte bis annimmt und für jeden Wert von x einen Befehl ausführt. In diesem Fall soll ein Text mit dem aktuellen Wert von x verknüpft und ausgegeben werden: > for (x in 3:5) {print(paste("Der Wert von x ist:",x))} Die Schleife erzeugt folgenden Output: [1] "Der Wert von x ist: 3" [1] "Der Wert von x ist: 4" [1] "Der Wert von x ist: 5" Die Konstruktion kann auch mit einer while Schleife erreicht werden. Dann muss man sich allerdings selbst eine Kontrollvariable konstruieren: > x< 2;n< 5; > while(x x < matrix(1:9,ncol=3,byrow=F);x [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9 Die Ermittlung der Spaltensummen können wir nun vornehmen, indemwir die konstruierteMatrix x demFunktionsparameterX übergeben und festlegen, dass die Summenfunktion (Fun=sum) auf die Spalten (MARGIN=2) angewendet wird: > apply(X=x,MARGIN=2,FUN=sum) [1] 6 15 24 Anstelle der Benennung der übergebenen Objekte und Optionen kann im Funktionsaufruf auch nur auf die Einhaltung der Reihenfolge der Argumente und Optionen geachtet werden: > apply(x,2,sum) lapply Der Befehl lapply(X,FUN) funktioniert analog dem Befehl apply(), nur wird hier die Funktion nicht auf Zeilen oder Spalten einer Matrix, sondern auf Elemente einer Liste angewendet. Wir erzeugen zunächst eine Liste (Sammlung von Objekten) mit drei Elementen (Objekten) a,b und d: > x < list(a=1:7,b=exp( 2:2),d=c(TRUE,FALSE,FALSE,TRUE));x $a [1] 1 2 3 4 5 6 7 $b [1] 0.1353353 0.3678794 1.0000000 2.7182818 7.3890561 $d [1] TRUE FALSE FALSE TRUE Die Vergabe von Namen für die Elemente der Liste im list() Befehl erfolgt also durch Voranstellen des Namens (ohne Anführungsstriche), gefolgt von = und einer Angabe des Elements. Da das Ergebnis des list() Befehls eine Liste ist, können ganz unterschiedliche Objekte (hier: Objekte unterschiedlichen Typs) mit unterschiedlichen Längen (hier: c(7,5,4)) zusammengestellt werden. Auf jedes Element der Liste soll nun die Funktion sum() angewendet werden. > lapply(x,sum) $a [1] 28 $b [1] 11.61055 $d [1] 2 Das Ergebnis der Funktion lapply() ist eine Liste mit der gleichen Anzahl an Elementen wie in der auszuwertenden Liste. Zu bemerken ist auch, dass das Rechenoperationen und Programmablauf in R Element d der Liste ein Vektor logischer Werte ist. Bei der Berechnung der Summe werden also zunächst alle logischen Werte in den Typ numeric verwandelt (TRUE wird zu , FALSE zu ), erst dann wird die Summe berechnet. sapply Die Funktion sapply(X,FUN) ist eine anwenderfreundliche Verallgemeinerung der Funktion lapply(), die nicht nur Listen, sondern auch Vektoren oder Matrizen verarbeiten kann. Die Anwendung auf die oben erzeugte Liste führt zu folgendem Ergebnis: > sapply(x,sum) a b d 28.00000 11.61055 2.00000 Während lapply() eine Liste zurückgibt, erhalten wir mit sapply() eine Ergebnismatrix. mapply und Map Map() ist eine Erweiterung von lapply, bei der die jeweiligen Elemente mehrerer Listen (oder Vektoren) durch die Funktion FUN ausgewertet werden. Die Funktion FUN muss natürlich entsprechend viele Argumente akzeptieren. mapply(FUN,...) entspricht Map(), vereinfacht aber ebenso wie sapply() das Ergebnis. tapply und by Die Funktion tapply(X,INDEX,FUN) dient zur gruppenweisen Auswertung eines Vektors. Die Aufgabe ist nicht mehr, für alle Variablen einer Liste (eines Dataframes etc.) Statistiken zu berechnen, sondern für eine Variable Statistiken für alle durch den INDEX unterschiedenen Teilgruppen zu berechnen. Der Funktion muss der auszuwertende Vektor X, die Gruppierungsvariable INDEX gleicher Länge und die für jede Gruppe anzuwendende Funktion FUN übergeben werden. INDEX wird in den Typ factor verwandelt, wenn es noch kein Faktor ist. INDEX kann auch eine Liste von Indizes sein. Dann werden Untergruppen durch gleiche Merkmalswerte der Liste der Indizes gebildet. tapply() akzeptiert als erstes Argument nur einen Vektor. Oft stellt sich aber das Problem, etwa in einem Dataframe mit mehreren Variablen gleichzeitig zu arbeiten. Das kann erreicht werden, indem als erstes Argument ein Laufindex für die Zeilen des Dataframes benutzt wird. Hat man etwa zwei Einkommensarten und möchte das durchschnittliche Gesamteinkommen getrennt nach Geschlechtern berechnen, dann kann man schreiben: > Einkommen1 < c(2000,1400,1000) > Einkommen2 < c(200,500,300) > Geschlecht < c(0,1,0) . Programmablauf > dat1 < data.frame(Geschlecht,Einkommen1,Einkommen2) > tapply(1:nrow(dat1),dat1$Geschlecht, + function(i){ + mean(dat1$Einkommen1[i]+dat1$Einkommen2[i])}) 0 1 1750 1900 Die Funktion by(data,INDEX,FUN) kürzt diese Vorgehensweise ab: > by(dat1,Geschlecht,function(d){ mean(d$Einkommen1+d$Einkommen2)}) Geschlecht: 0 [1] 1750 Geschlecht: 1 [1] 1900 Zu beachten ist der Unterschied in der Übergabe an die Funktion FUN: In der Version, die direkt tapply() benutzt, werden die Zeilenindizes übergeben, die zu einer Gruppe gehören. Im Aufruf von by() wird die gesamte Teilmatrix (oder der Teil-Dataframe), der der Teilgruppe entspricht, als Argument an FUN übergeben. In letzterem Fall können die Namen des Dataframes benutzt werden. split und unsplit Die Funktion split(X,INDEX) erlaubt es, die Aufteilung eines Vektors (oder eines Dataframes), die durch tapply() bzw. by() implizit vorgenommen wird, auch explizit durchzuführen. Dabei ist X ein Vektor oder ein Dataframe und INDEX ein Faktor (oder eine Liste von Faktoren), nach dessen Werten X aufgeteilt wird. Das Ergebnis ist eine Liste, deren Elemente die entsprechenden Teilvektoren (oder Teilmatrizen oder Teildataframes) sind. unsplit(wert,INDEX) macht split(X,INDEX) rückgängig. Genauer: wenn wert = split(X,INDEX) ist, dann ist unsplit(wert,INDEX)=X. Mit den beiden Befehlen zusammen mit lapply() oder sapply() lässt sich für alle Datenstrukturen die Funktionsweise von by() nachmachen, ohne dass zunächst das Argument (implizit oder explizit) in einen Dataframe verwandelt wird. > a < split(dat1,dat1$Geschlecht);a $Ś0Ś Geschlecht Einkommen1 Einkommen2 1 0 2000 200 3 0 1000 300 $Ś1Ś Geschlecht Einkommen1 Einkommen2 2 1 1400 500 > lapply(a,function(d){ Rechenoperationen und Programmablauf in R + mean(d$Einkommen1+d$Einkommen2) }) $Ś0Ś [1] 1750 $Ś1Ś [1] 1900 unsplit() kann nun genutzt werden, das Ergebnis wieder den einzelnen Beobachtungen zuzuordnen: > unsplit(lapply(a,function(d){ + mean(d$Einkommen1+d$Einkommen2) + } ),dat1$Geschlecht) [1] 1750 1900 1750 . . Bedingte Anweisungen Wenn die Ausführung von Befehlen von Bedingungen abhängen soll, kann man konditionale Anweisungen benutzen. Wie Schleifen werden konditionale Anweisungen durch drei Teile angegeben: Vorangestellt der Befehl if, dann in runden Klammern ein logischer Ausdruck, der festlegt, ob der nachfolgende Befehl ausgeführt werden soll oder nicht, und im Anschluss (in geschweiften Klammern) ein Befehl oder ein Block von Befehlen, die beim Zutreffen der Bedingung abgearbeitet werden. Eine Alternative, die ausgeführt wird, wenn die Bedingung falsch ist, kann nach demWort else angeführt werden. > x < 0:2 > if(min(x) > 0)log(x) else log(x + min(x)+0.001) [1] 6.9077552790 0.0009995003 0.6936470556 Die if() Konstruktion benutzt als Bedingung nur einen skalaren Wahrheitswert. Wird ein Vektor von Wahrheitswerten in der Bedingung berechnet oder angegeben, dann wird nur das erste Element des Vektors benutzt (und es wird eine Warnung ausgegeben). Das Konstrukt if(){ }else{ } findet sich in fast allen höheren Programmiersprachen und dient, ebenso wie das Schleifen-Konstrukt, der Kontrolle des Programmablaufs. Im Zusammenhang mit statistischen Daten tritt aber viel häufiger die Notwendigkeit auf, Werte einzelner Variablen umzukodieren oder in Abhängigkeit von denWerten anderer Variablen neue Variable zu berechnen. Dafür stellt R den Befehl ifelse() bereit.Die Funktion hat drei Argumente, als erstes einen Vektor vonWahrheitswerten (oder einen Ausdruck, dessen Auswertung einen entsprechenden Vektor liefert). Dann folgt ein Vektor, dessen n-tes Element zurückgegeben wird, wenn das n-te Element des Bedingungsvektors wahr ist, an dritter Stelle dann ein Vektor, dessen n-tes Element zurückgegeben wird, wenn das n-te Element des Bedingungsvektors falsch ist. > ifelse(x>0,log(x),NA) [1] NA 0.0000000 0.6931472 . Übungsaufgaben In der ifelse() Funktion werden immer sowohl das zweite wie das dritte Argument ausgewertet. Das obere Beispiel würde deshalb eineWarnung produzieren, wenn negative Werte in x auftreten. > x < 1:1 > ifelse(x>0,log(x),NA) [1] NA NA 0 Warnmeldung: In log(x) : NaNs wurden erzeugt In diesem Fall ist es besser, die Rechenanweisung nach der ifelse() Funktion auszuführen. > log(ifelse(x>0,x,NA)) [1] NA NA 0 Oft kann die ifelse() Funktion auch durch entsprechende Konstruktionen mit logischen Indizes ersetzt werden. > y < rep(NA,length(x)) #Vektor der Ergebnisse > y[x>0] < log(x[x>0]) > y [1] NA NA 0 Eine besonders einfache und effiziente Variante, die oft zur Umkodierung von Variablenwerten benutzt werden kann, wird in den Übungen vorgestellt. . Übungsaufgaben 1) Erzeugen Sie eine Sequenz von bis und weisen Sie die Sequenz der Variablen a zu. 2) Erzeugen Sie den Vektor b=(1,1,1,2,2,2,3,3,3). 3) Erzeugen Sie den Vektor d=(1,2,3,1,2,3,1,2,3). 4) Erzeugen Sie den Vektor e=(1,2,2,3,3,3,4,4,4). 5) Erzeugen Sie aus den vier Vektoren a,b,d,e eine Matrix. 6) Erzeugen Sie aus den vier Vektoren a,b,d,e einen Dataframe. 7) Ändern Sie die Namen der vier Variablen des Dataframes in alpha, beta, gamma, delta. 8) Erzeugen Sie einen Vektor, der angibt, ob beta==2 ist. 9) Berechnen Sie: + ( + ( + ( + ))), , loge( ), . 10) Berechnen Sie i= . i und i= i . 11) Schreiben Sie eine Funktion, die zu den Argumenten x und y den Wert der folgenden Funktion berechnet: y + x x y y y + y Berechnen Sie den Funktionswert für x = und y = .Hinweis: Die Lösung ist ! Um wieviel Prozent weicht die Antwort von R ab? Rechenoperationen und Programmablauf in R Können Sie die korrekte Antwort mit einem Programm, das mit exakten großen ganzen Zahlen rechnen kann, verifizieren? In Frage kommt mathematische Software wie Maxima, Sage, YACAS, Mathematica etc. Wer ein wenig mit den Möglichkeiten von R spielen möchte, kann aber auch das R Paket gmp (GNU multiple precision library) ausprobieren. 12) Schreiben Sie eine Funktion, die die Fakultät n! := n (n ) (n ) . . . ohne Rückgriff auf die Gammafunktion berechnet. 13) Berechnen Sie getrennt für die durch die Variable beta definierten Gruppen im Dataframe aus Aufgabe ) den Durchschnitt der Variablen gamma. Wiederholen Sie die Berechnung für Gruppen, die durch die beiden Variablen beta und delta gemeinsam definiert sind. 14) Der Vektor beta im Dataframe nimmt nur die Werte 1,2,3 an. Der folgenden Zeilen kodieren die Werte neu und ersetzen 1 durch 0, 2 durch 5 und 3 durch 97: > code < c(0,5,97) > beta2 < code[dat$beta] Schreiben Sie den entsprechenden Code unter Verwendung der ifelse() Funktion. 15) Untersuchen Sie drei Versionen, Mittelwerte für alle Variablen eines Dataframe zu berechnen. Erstellen Sie dazu zunächst einen entsprechenden Dataframe: > d < matrix(1:100000,nrow=10) > dd < data.frame(d) Die Laufzeit eines Programms oder Befehls kann durch system.time() abgefragt werden. Die erste Version könnte sein: > e < numeric(0) #initialisiert Ergebnisvektor > system.time(for(i in 1:10000) e <- c(e,mean(d[,i]))) In dieser Schleife wird bei jeder Zuweisung der Vektor e kopiert. Die zweite Version bildet erst den Ergebnisvektor e und weist in der Schleife nur noch den Elementen von e die Ergebnisse zu: > e < numeric(10000) > system.time(for(i in 1:10000) e[i] <- mean(d[,i])) Die letzte Version nutzt lapply() > system.time(e <- lapply(dd,mean)) Das Anhängen von Ergebnissen in Schleifen über e < c(e,wert) ist auf jeden Fall zu vermeiden. Selbst wenn dieser Ratschlag berücksichtigt wird, ist die Verwendung von lapply() der Verwendung einer Schleife vorzuziehen, nicht nur, weil es u.U. deutlich schneller ist, sondern vor allem, weil der Code sehr viel übersichtlicher wird.

Chapter Preview

References

Zusammenfassung

Vorteile

- Einführung in die statistische Analyse mit R für Wirtschafts- und Sozialwissenschaftler

- Inklusive hilfreicher Tipps wie "Ansprechende Grafiken mit R gestalten"

Zum Thema

R ist ein Statistikprogramm, das kostenlos über das Internet verbreitet wird und dessen Source Codes frei zugänglich sind.

Aufgrund dieses kostenlosen Angebots gehen immer mehr Dozenten dazu über, neben SPSS auch R zu lehren bzw. SPSS durch R zu ersetzen.

In R steht dem Nutzer die gesamte Bandbreite statistischer Verfahren zur Verfügung. Durch die eigenständige Programmierumgebung ist die Software sehr flexibel und erlaubt notwendige Modifikationen und Erweiterungen verfügbarer Prozeduren.

Zum Werk

Dieses Buch führt leicht verständlich in die statistische Analyse mit R ein. Anhand von Beispielen wird die Umsetzung der wichtigsten Methoden der Statistik, wie sie üblicherweise in den Grundkursen gelehrt werden, mit R vorgestellt.

Das Buch verfolgt entsprechend zwei Ziele:

1. Vorstellung der statistischen Methoden,

2. Benutzung des Werkzeuges R zur Analyse von Daten.

Inhalt

- Grundlagen von R

- Datenbehandlung und graphische Darstellungen mit R

- Datenbeschreibungen (deskriptive Statistik)

- Wahrscheinlichkeitsverteilungen

- Regressionsanalysen

- Optimierungsverfahren

- Simulationen mit R

Neben vielen neuen, wirtschaftsorientierten Beispielen wird nun auch in die Paneldatenanalyse und Stichprobentheorie eingeführt.

Zu den Autoren

Dr. Andreas Behr ist wissenschaftlicher Mitarbeiter am Institut für Statistik und Ökonometrie der Universität Münster.

Dr. Ulrich Pötter ist wissenschaftlicher Mitarbeiter am Institut für Statistik der Universität Bochum.

Zielgruppe

Für Studierende und Dozenten der Wirtschaftswissenschaften im Bachelor an Universitäten und Fachhochschulen.