R-Grundlagen

Programmiergrundlagen
R
Python
Vektoren, Data Frames, Funktionen und die Eigenheiten von R.

Kernideen

  • Alles ist ein Vektor, auch der einzelne Wert. Rechnungen laufen elementweise über den ganzen Vektor, ohne Schleife.
  • Recycling: Ist ein Vektor kürzer, wiederholt R ihn. Das ist bei einer einzelnen Zahl bequem und bei unpassenden Längen eine stille Fehlerquelle.
  • Ein Vektor, ein Typ. Treffen Typen aufeinander, wandelt R still in den allgemeineren um: logisch, dann Zahl, dann Text.
  • Faktoren sind Kategorien mit festgelegten Stufen. Die Stufen bestimmen Tabellen, Reihenfolgen und Referenzkategorien.
  • Der Data Frame ist eine Liste gleich langer Spalten: jede Zeile eine Beobachtung, jede Spalte ein Merkmal.
  • Liste für Ungleichartiges, Matrix für Zahlen in Zeilen und Spalten. R füllt Matrizen spaltenweise, NumPy zeilenweise.

Erklärung

Vorwissen: keines. Diese Seite setzt weder Statistik noch Programmiererfahrung voraus. Wer von Python kommt, findet den Vergleich in jedem Beispiel; die Python-Seite dazu ist Python-Grundlagen. Die Datenstrukturen von hier tauchen im Data Wrangling auf jeder Zeile wieder auf, und wie man daraus reproduzierbare Auswertungen macht, steht unter Reproduzierbarkeit.

Wozu eine eigene Sprache für Daten

Eine Tabellenkalkulation kommt weit. Sie stösst dort an ihre Grenze, wo eine Auswertung wiederholbar sein soll: Wer dieselbe Analyse mit neuen Zahlen braucht, klickt sie erneut zusammen und weiss hinterher nicht sicher, ob dieselben Schritte in derselben Reihenfolge erwischt wurden. Ein Skript beantwortet diese Frage, weil jeder Schritt darin nachlesbar ist.

R ist für genau diesen Zweck entstanden, nicht als allgemeine Programmiersprache mit angebauter Statistik. Das erklärt einige Eigenheiten, die zunächst ungewohnt wirken und später Arbeit sparen.

Alles ist ein Vektor

In vielen Sprachen ist die Grundeinheit die einzelne Zahl, und wer fünfhundert Messwerte umrechnen will, schreibt eine Schleife. In R ist die Grundeinheit die Folge von Werten, und ein einzelner Wert ist eine Folge der Länge eins. Deshalb wirkt werte / 10 auf jeden Wert, und werte > 20 liefert für jeden Wert ein TRUE oder FALSE. Summiert man diese Wahrheitswerte, zählt man die Treffer, weil TRUE beim Rechnen als 1 gilt; ihr Mittelwert ist der Anteil.

Python bringt das nicht von Haus aus mit. Eine Python-Liste rechnet nicht elementweise; das Verhalten von R entsteht erst mit einem NumPy-Array, siehe NumPy und SciPy.

Recycling

Sind zwei Vektoren unterschiedlich lang, wiederholt R den kürzeren, bis er passt. Bei werte / 10 ist das der Grund, warum die eine 10 auf alle Werte angewendet wird. Geht die Länge des längeren nicht in einem Vielfachen auf, gibt R eine Warnung aus und rechnet trotzdem. Geht sie auf, rechnet R ohne jeden Hinweis, auch wenn die Absicht eine andere war.

NumPy folgt einer engeren Regel, dem Broadcasting: Formen werden von hinten verglichen und nur dort angeglichen, wo eine Achse die Länge eins hat. Sonst bricht die Rechnung ab.

Ein Vektor, ein Typ

Ein Vektor trägt genau einen Typ. Treffen verschiedene Typen aufeinander, wandelt R sie in den allgemeineren um, statt einen Fehler zu melden. Dieser Vorgang heisst Coercion, und die Rangfolge lautet

\[ \text{logisch} \;\rightarrow\; \text{ganze Zahl} \;\rightarrow\; \text{Gleitkommazahl} \;\rightarrow\; \text{Text} \]

Ein einziger Texteintrag in einer Spalte, etwa ein Strich für einen fehlenden Wert, verwandelt deshalb die ganze Spalte in Text. Die Kontrolle der Spaltentypen gehört direkt hinter jeden Import.

Faktoren

Kategoriale Merkmale liessen sich als Text speichern. Damit ginge verloren, welche Ausprägungen überhaupt möglich sind und in welcher Reihenfolge sie stehen. Der Faktor führt die Stufen (levels) als eigene Eigenschaft mit. Intern speichert er ganze Zahlen, die auf die Stufen zeigen; das ist der Grund für die bekannteste Faktor-Falle in Beispiel 4. Das Gegenstück in pandas ist pd.Categorical.

Eigenschaft Faktor ohne Vorgabe Faktor mit levels geordneter Faktor
Stufen aus den Daten, alphabetisch wie vorgegeben, auch unbesetzte wie vorgegeben
Vergleich <, > nicht sinnvoll nicht sinnvoll erlaubt
typischer Fall Gerätetyp, Standort Umfrage mit fester Antwortliste Bewertungsskala

Data Frame, Liste, Matrix

Struktur Inhalt Typen Python
Vektor eine Folge einer NumPy-Array, pd.Series
Data Frame gleich lange Spalten je Spalte einer pd.DataFrame
Liste beliebige Objekte unter Namen beliebig Dictionary
Matrix Zahlen in Zeilen und Spalten einer zweidimensionales NumPy-Array

Der Data Frame ist genau genommen eine Liste gleich langer Vektoren. Deshalb funktioniert df$spalte wie bei einer Liste, und deshalb dürfen die Spalten verschiedene Typen tragen, aber nicht verschieden lang sein: Sonst ginge die Zuordnung zur Beobachtung verloren.

Beim Auswählen trennt das Komma Zeilen von Spalten: df[zeilen, spalten]. Ein leerer Platz heisst “alle”. df[df$gruppe == "A", ] wählt alle Zeilen der Gruppe A und alle Spalten; innen steht eine Bedingung, die für jede Zeile wahr oder falsch ist.

Kurz nachgeschlagen

Aufgabe R Python
Struktur ansehen str(df) df.dtypes, df.info()
Kennzahlen je Spalte summary(df) df.describe()
Zeilen und Spalten wählen df[df$x > 40, c("a", "b")] df.loc[df["x"] > 40, ["a", "b"]]
Spalte anlegen df$neu <- df$a / df$b df["neu"] = df["a"] / df["b"]
Mittel je Gruppe tapply(df$x, df$g, mean) df.groupby("g")["x"].mean()
Stufen festlegen factor(x, levels = c(...)) pd.Categorical(x, categories=[...])
unbesetzte Stufen entfernen droplevels(f) s.cat.remove_unused_categories()
Zahlen aus einem Faktor as.numeric(as.character(f)) s.astype(float)
fehlende Werte zählen sum(is.na(x)) s.isna().sum()
Länge prüfen stopifnot(length(x) == n) assert len(x) == n

Beispiele

Frage und Datenlage

Vier Messwerte 12, 45, 7, 31. Sie sollen durch 10 geteilt werden, es soll gezählt werden, wie viele über 20 liegen, und welcher Anteil das ist. Dazu die Multiplikation mit einem zweiten Vektor gleicher Länge.

Rechnung

x <- 5
length(x)
[1] 1
is.vector(x)
[1] TRUE
werte <- c(12, 45, 7, 31)
werte / 10
[1] 1.2 4.5 0.7 3.1
werte > 20
[1] FALSE  TRUE FALSE  TRUE
sum(werte > 20)
[1] 2
mean(werte > 20)
[1] 0.5
werte * c(10, 20, 30, 40)
[1]  120  900  210 1240
x = 5
print(type(x).__name__, np.array([5]).shape)
int (1,)
werte = np.array([12, 45, 7, 31])
print(werte / 10)
[1.2 4.5 0.7 3.1]
print(werte > 20)
[False  True False  True]
print((werte > 20).sum(), (werte > 20).mean())
2 0.5
print(werte * np.array([10, 20, 30, 40]))
[ 120  900  210 1240]

Output Zeile für Zeile

Ausdruck R Python Erklärung
einzelner Wert Länge 1, is.vector ist TRUE int, erst als Array Form (1,) In R ist die 5 ein Vektor, in Python eine einzelne Zahl.
werte / 10 1.2 4.5 0.7 3.1 [1.2 4.5 0.7 3.1] Die eine 10 wird auf alle vier Werte angewendet.
werte > 20 FALSE TRUE FALSE TRUE [False True False True] Ein Wahrheitswert je Messwert.
Summe der Wahrheitswerte 2 2 Anzahl der Werte über 20: 45 und 31.
Mittel der Wahrheitswerte 0.5 0.5 Anteil der Werte über 20.
paarweise mal 120 900 210 1240 [ 120 900 210 1240] Erstes mit erstem, zweites mit zweitem. Kein Skalarprodukt; das wäre %*% beziehungsweise @.

Interpretation und Ergebnissatz

Das Muster sum(bedingung) und mean(bedingung) taucht in jeder Auswertung auf: Aus einer Bedingung wird ohne Schleife eine Anzahl oder ein Anteil. In Python gilt dasselbe, sobald die Werte in einem NumPy-Array oder einer pandas-Series stehen.

Zwei der vier Messwerte liegen über 20, das ist ein Anteil von 0.5. Die Rechnung läuft in R auf dem Vektor selbst, in Python erst nach der Umwandlung in ein NumPy-Array.

Frage und Datenlage

Ein Vektor mit sechs Werten 1 bis 6 wird mit einem Vektor der Länge zwei (10, 100) und einem der Länge vier (10, 100, 1000, 10000) multipliziert. Was tut R, was tut NumPy?

Rechnung

lang <- c(1, 2, 3, 4, 5, 6)
kurz <- c(10, 100)

lang * kurz                          # 6 ist ein Vielfaches von 2: kein Hinweis
[1]  10 200  30 400  50 600
vier <- c(10, 100, 1000, 10000)
tryCatch(lang * vier, warning = function(w) conditionMessage(w))
[1] "longer object length is not a multiple of shorter object length"
suppressWarnings(lang * vier)        # gerechnet wird trotzdem
[1]    10   200  3000 40000    50   600
# Kontrolle vor der Rechnung
stopifnot(length(lang) %% length(kurz) == 0)
lang = np.array([1, 2, 3, 4, 5, 6])
kurz = np.array([10, 100])

try:
    lang * kurz
except ValueError as fehler:
    print("ValueError:", fehler)
ValueError: operands could not be broadcast together with shapes (6,) (2,) 
print(lang * 10)                         # eine Zahl passt immer
[10 20 30 40 50 60]
print(lang.reshape(3, 2) * kurz)         # passende Achse: Broadcasting
[[ 10 200]
 [ 30 400]
 [ 50 600]]

Output Zeile für Zeile

Rechnung R Python Erklärung
sechs mal zwei 10 200 30 400 50 600, ohne Hinweis ValueError, Formen (6,) und (2,) passen nicht R wiederholt 10, 100 dreimal. Ob das gemeint war, prüft niemand.
sechs mal vier Warnung longer object length is not a multiple of shorter object length 6 ist kein Vielfaches von 4. R warnt, rechnet aber: 10, 200, 3000, 40000, 50, 600.
mal eine Zahl 10 20 30 40 50 60 Eine Zahl hat die Form () und passt zu jeder Form.
(3, 2) mal (2,) Zeilen 10 200, 30 400, 50 600 Von hinten verglichen stimmen die 2 überein; die Zeile 10, 100 wird auf jede der drei Zeilen angewendet.
stopifnot kein Output Die Annahme stimmt, also läuft das Skript weiter. Stimmte sie nicht, bräche es an dieser Stelle ab.

Interpretation und Ergebnissatz

Der gefährliche Fall ist nicht die Warnung, sondern die Stille: Sechs mal zwei liefert ein plausibel aussehendes Ergebnis ohne jeden Hinweis. NumPy verlangt, dass die Formen ausdrücklich zusammenpassen, und gleicht nur Achsen der Länge eins an. Wer in R mit Vektoren unterschiedlicher Länge rechnet, sollte die Längen vorher mit stopifnot festschreiben.

Die Multiplikation eines Vektors der Länge sechs mit einem der Länge zwei ergibt in R ohne Hinweis 10 200 30 400 50 600; NumPy bricht mit einem ValueError ab. Bei Länge vier warnt R, rechnet aber dennoch.

Frage und Datenlage

Welchen Typ erhält ein Vektor aus Wahrheitswert, Zahl und Text? Und was passiert beim Einlesen einer CSV-Datei, in der ein fehlender Wert als Strich eingetragen ist (1.5, -, 2.0)?

Rechnung

class(c(TRUE, FALSE))
[1] "logical"
class(c(TRUE, 3))
[1] "numeric"
class(c(TRUE, 3, "drei"))
[1] "character"
c(TRUE, 3, "drei")
[1] "TRUE" "3"    "drei"
csv_text <- "id,wert\n1,1.5\n2,-\n3,2.0"
roh <- read.csv(text = csv_text)
class(roh$wert)
[1] "character"
roh$wert
[1] "1.5" "-"   "2.0"
zahlen <- suppressWarnings(as.numeric(roh$wert))
zahlen
[1] 1.5  NA 2.0
sum(zahlen, na.rm = TRUE)
[1] 3.5
sauber <- read.csv(text = csv_text, na.strings = "-")
class(sauber$wert)
[1] "numeric"
print(pd.Series([1, 2, "3"]).dtype)
object
csv_text = "id,wert\n1,1.5\n2,-\n3,2.0\n"
roh = pd.read_csv(io.StringIO(csv_text))
print(roh["wert"].dtype, roh["wert"].tolist())
object ['1.5', '-', '2.0']
zahlen = pd.to_numeric(roh["wert"], errors="coerce")
print(zahlen.tolist(), zahlen.sum())
[1.5, nan, 2.0] 3.5
sauber = pd.read_csv(io.StringIO(csv_text), na_values="-")
print(sauber["wert"].dtype)
float64

Output Zeile für Zeile

Schritt R Python Erklärung
logisch und logisch logical
logisch und Zahl numeric TRUE wird zu 1.
dazu ein Text character, Inhalt "TRUE" "3" "drei" gemischte Series: object Alles wird Text, auch die 3 und das TRUE. pandas hält gemischte Werte als allgemeine Objekte.
Spalte mit Strich character, "1.5" "-" "2.0" Textspalte, ['1.5', '-', '2.0'] Der eine Strich macht die ganze Spalte zu Text. Rechnen ist damit nicht mehr möglich.
umgewandelt 1.5 NA 2.0 [1.5, nan, 2.0] as.numeric beziehungsweise to_numeric(errors="coerce") machen aus dem Strich einen fehlenden Wert.
Summe 3.5 3.5 Ohne den fehlenden Wert.
mit Angabe beim Import numeric float64 Der bessere Weg: dem Import sagen, was “fehlend” bedeutet.

Interpretation und Ergebnissatz

Coercion ist eine Regel und kein Fehler, und deshalb meldet sie sich nicht. Die Spalte sieht in der Vorschau richtig aus, und der Fehler zeigt sich erst, wenn eine Rechnung scheitert oder ein Mittelwert fehlt. Die Abhilfe gehört an den Anfang: fehlende Werte beim Import deklarieren (na.strings, na_values) und danach die Typen mit str() beziehungsweise df.dtypes kontrollieren.

Ein einziger Strich in der Spalte wert machte beim Einlesen die ganze Spalte zu Text. Mit na.strings = "-" beziehungsweise na_values="-" wird sie als Zahl gelesen, und die Summe der beiden gültigen Werte beträgt 3.5.

Frage und Datenlage

Fünf Umfrageantworten (ja, nein, ja, ja, nein) auf die Antwortliste ja, nein, weiss nicht. Dann Schulnoten 5, 3, 4 als Faktor und eine Bewertungsskala von schlecht bis ausgezeichnet.

Rechnung

antworten <- c("ja", "nein", "ja", "ja", "nein")
als_faktor <- factor(antworten, levels = c("ja", "nein", "weiss nicht"))
levels(als_faktor)
[1] "ja"          "nein"        "weiss nicht"
table(als_faktor)
als_faktor
         ja        nein weiss nicht 
          3           2           0 
table(factor(antworten))

  ja nein 
   3    2 
noten <- factor(c(5, 3, 4))
as.numeric(noten)                    # die internen Codes
[1] 3 1 2
as.numeric(as.character(noten))      # die Werte
[1] 5 3 4
skala <- factor(c("gut", "schlecht", "ausgezeichnet", "gut"),
                levels = c("schlecht", "gut", "ausgezeichnet"), ordered = TRUE)
sort(skala)
[1] schlecht      gut           gut           ausgezeichnet
Levels: schlecht < gut < ausgezeichnet
skala > "schlecht"
[1]  TRUE FALSE  TRUE  TRUE
antworten = ["ja", "nein", "ja", "ja", "nein"]
kat = pd.Categorical(antworten, categories=["ja", "nein", "weiss nicht"])
print(kat.categories.tolist())
['ja', 'nein', 'weiss nicht']
print(pd.Series(kat).value_counts(sort=False).to_dict())
{'ja': 3, 'nein': 2, 'weiss nicht': 0}
print(pd.Series(antworten).value_counts().to_dict())
{'ja': 3, 'nein': 2}
noten = pd.Categorical([5, 3, 4])
print(noten.categories.tolist(), noten.codes.tolist())
[3, 4, 5] [2, 0, 1]
skala = pd.Categorical(["gut", "schlecht", "ausgezeichnet", "gut"],
                       categories=["schlecht", "gut", "ausgezeichnet"],
                       ordered=True)
print(list(skala.sort_values()))
['schlecht', 'gut', 'gut', 'ausgezeichnet']
print((skala > "schlecht").tolist())
[True, False, True, True]

Output Zeile für Zeile

Schritt R Python Erklärung
Stufen ja, nein, weiss nicht dieselben wie vorgegeben
Häufigkeiten mit Stufen ja 3, nein 2, weiss nicht 0 {'ja': 3, 'nein': 2, 'weiss nicht': 0} Die unbesetzte Stufe bleibt sichtbar. Für eine Umfrage ist das die vollständige Information.
Häufigkeiten ohne Vorgabe ja 3, nein 2 {'ja': 3, 'nein': 2} Was niemand gewählt hat, existiert nicht.
as.numeric(noten) 3 1 2 Codes [2, 0, 1] Die internen Codes, also die Position in der sortierten Stufenliste 3, 4, 5. Die Note 5 steht an dritter Stelle. pandas zählt ab null.
über as.character 5 3 4 der sichere Weg zurück zu den Werten
geordnet sortiert schlecht, gut, gut, ausgezeichnet dieselbe Folge Nach den Stufen, nicht alphabetisch; alphabetisch stünde ausgezeichnet vorne.
> "schlecht" TRUE FALSE TRUE TRUE [True, False, True, True] Vergleiche sind nur bei geordneten Faktoren sinnvoll.

Interpretation und Ergebnissatz

Die Stufen sind keine Beschriftung, sondern Teil der Daten. Sie bestimmen, welche Kategorien in Tabellen erscheinen, in welcher Reihenfolge Balken in einem Diagramm stehen und welche Stufe in einem Regressionsmodell als Referenz dient, siehe multiple lineare Regression. Die Faktor-Falle mit as.numeric ist die häufigste stille Fehlerquelle: Die Rechnung läuft, nur mit den Codes 3, 1, 2 statt mit den Noten 5, 3, 4.

Mit vorgegebenen Stufen weist die Tabelle weiss nicht mit 0 aus, ohne Vorgabe fehlt die Stufe. as.numeric auf dem Notenfaktor liefert die Codes 3, 1, 2 statt der Noten 5, 3, 4; richtig ist as.numeric(as.character()).

Frage und Datenlage

Fünf Beobachtungen mit Kennnummer, Messwert (2.5, 3.1, 4.0, 2.8, 3.6) und Gruppe (A, B, A, B, A). Struktur ansehen, Kennzahlen, Zeilen der Gruppe A auswählen, Mittelwert je Gruppe.

Rechnung

df <- data.frame(
  id     = 1:5,
  wert   = c(2.5, 3.1, 4.0, 2.8, 3.6),
  gruppe = factor(c("A", "B", "A", "B", "A"))
)
str(df)
'data.frame':   5 obs. of  3 variables:
 $ id    : int  1 2 3 4 5
 $ wert  : num  2.5 3.1 4 2.8 3.6
 $ gruppe: Factor w/ 2 levels "A","B": 1 2 1 2 1
summary(df$wert)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    2.5     2.8     3.1     3.2     3.6     4.0 
round(sd(df$wert), 3)
[1] 0.604
df[df$gruppe == "A", ]
  id wert gruppe
1  1  2.5      A
3  3  4.0      A
5  5  3.6      A
tapply(df$wert, df$gruppe, mean)
       A        B 
3.366667 2.950000 
df = pd.DataFrame({
    "id":     [1, 2, 3, 4, 5],
    "wert":   [2.5, 3.1, 4.0, 2.8, 3.6],
    "gruppe": pd.Categorical(["A", "B", "A", "B", "A"]),
})
print(df.shape)
(5, 3)
print(df.dtypes)
id           int64
wert       float64
gruppe    category
dtype: object
print(df["wert"].describe().round(3))
count    5.000
mean     3.200
std      0.604
min      2.500
25%      2.800
50%      3.100
75%      3.600
max      4.000
Name: wert, dtype: float64
print(df[df["gruppe"] == "A"])
   id  wert gruppe
0   1   2.5      A
2   3   4.0      A
4   5   3.6      A
print(df.groupby("gruppe", observed=True)["wert"].mean().round(4))
gruppe
A    3.3667
B    2.9500
Name: wert, dtype: float64

Output Zeile für Zeile

Grösse R Python Erklärung
Umfang 5 obs. of 3 variables (5, 3) Zeilen und Spalten. Die erste Kontrolle nach jedem Import.
Typ id int int64 1:5 erzeugt in R ganze Zahlen.
Typ wert num float64
Typ gruppe Factor w/ 2 levels "A","B": 1 2 1 2 1 category R zeigt die Stufen und die internen Codes.
Minimum, Maximum 2.5, 4.0 2.5, 4.0
Quartile 2.8, 3.1, 3.6 25 %, 50 %, 75 %: 2.8, 3.1, 3.6 Beide rechnen die Quantile nach derselben Voreinstellung.
Mittelwert 3.2 3.2
Standardabweichung 0.604 0.604 Nur describe zeigt sie von selbst, in R braucht es sd().
Zeilen der Gruppe A id 1, 3, 5 Index 0, 2, 4 Dieselben Zeilen; pandas zeigt den Index ab null, R die Zeilennamen ab eins.
Mittel je Gruppe A 3.366667, B 2.950000 A 3.3667, B 2.95 (2.5 + 4.0 + 3.6) / 3 und (3.1 + 2.8) / 2

Interpretation und Ergebnissatz

str() in R und df.dtypes in Python sind die Befehle, die nach jedem Import zuerst kommen: Sie zeigen, ob die Zeilenzahl plausibel ist und ob jede Spalte den erwarteten Typ hat. Die Kennzahlen danach verteilen sich verschieden: summary bringt Quartile und Mittelwert, describe zusätzlich Anzahl und Standardabweichung. Was diese Kennzahlen bedeuten, steht unter Lage- und Streuungsmasse.

Die fünf Messwerte reichen von 2.5 bis 4.0 bei einem Mittelwert von 3.2 und einer Standardabweichung von 0.604. Gruppe A liegt im Mittel bei 3.37, Gruppe B bei 2.95.

Frage und Datenlage

Ein Ergebnis mit Text, drei Zahlen und einer Anzahl soll zusammengehalten werden, das passt in keine Tabelle. Danach eine Matrix aus den Zahlen 1 bis 6 mit zwei Zeilen: in welcher Reihenfolge wird sie gefüllt?

Rechnung

ergebnis <- list(methode = "Beispiel", werte = c(1.2, 3.4, 5.6), n = 3)
str(ergebnis)
List of 3
 $ methode: chr "Beispiel"
 $ werte  : num [1:3] 1.2 3.4 5.6
 $ n      : num 3
ergebnis$werte
[1] 1.2 3.4 5.6
m <- matrix(1:6, nrow = 2)
m
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
dim(m)
[1] 2 3
matrix(1:6, nrow = 2, byrow = TRUE)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
ergebnis = {"methode": "Beispiel", "werte": [1.2, 3.4, 5.6], "n": 3}
print(ergebnis["werte"], len(ergebnis))
[1.2, 3.4, 5.6] 3
print(np.arange(1, 7).reshape(2, 3))
[[1 2 3]
 [4 5 6]]
print(np.arange(1, 7).reshape(2, 3).shape)
(2, 3)
print(np.arange(1, 7).reshape(2, 3, order="F"))
[[1 3 5]
 [2 4 6]]

Output Zeile für Zeile

Schritt R Python Erklärung
Ergebnis List of 3 mit chr, num [1:3], num Dictionary mit drei Einträgen Beliebige Objekte unter Namen.
ergebnis$werte 1.2 3.4 5.6 [1.2, 3.4, 5.6]
Matrix, Voreinstellung Zeilen 1 3 5 und 2 4 6 Zeilen [1 2 3] und [4 5 6] R füllt spaltenweise, NumPy zeilenweise. Derselbe Aufruf ergibt verschiedene Matrizen.
Dimension 2 3 (2, 3)
umgestellt byrow = TRUE: 1 2 3, 4 5 6 order="F": 1 3 5, 2 4 6 Mit diesen Argumenten füllt jede Sprache wie die andere. F steht für Fortran, das wie R spaltenweise speichert.

Interpretation und Ergebnissatz

Die Liste ist die Struktur, in der R fast alle Ergebnisse zurückgibt: Das Resultat von t.test() oder lm() ist eine Liste mit Klassenattribut. Die Matrix-Reihenfolge ist die Stelle, an der beim Übertragen von Code zwischen den Sprachen am leichtesten ein Fehler entsteht, der keine Meldung erzeugt: Beide Matrizen sind gültig, nur ist die eine die umsortierte andere.

Die Liste hält Text, drei Messwerte und eine Anzahl unter einem Namen zusammen. matrix(1:6, nrow = 2) füllt spaltenweise und ergibt die erste Zeile 1 3 5; reshape(2, 3) in NumPy füllt zeilenweise und ergibt 1 2 3.

Verständnisfragen

Was liefert c(2, 4, 6) * c(10, 20, 30)?

Die Zahl 280, also das Skalarprodukt
R fasst die beiden nicht als mathematische Vektoren auf. Für das Skalarprodukt gäbe es %*%.
Den Vektor 20 80 180
Richtig. Multipliziert wird paarweise, erstes mit erstem und so weiter.
Einen Fehler wegen fehlender Schleife
Genau die ist nicht nötig.

Bei den Werten 12, 45, 7, 31 ergibt mean(werte > 20) den Wert 0.5. Was sagt diese Zahl inhaltlich?

Der Mittelwert der Messwerte beträgt 0.5
Gemittelt wird nicht über die Messwerte, sondern über das Ergebnis des Vergleichs.
Die Hälfte der Messwerte liegt über 20
Richtig. Der Mittelwert von Wahrheitswerten ist der Anteil der wahren Fälle.
Es gibt 0.5 Werte über 20
Eine Anzahl kann nicht gebrochen sein. Für die Anzahl müsste sum statt mean stehen.

c(1, 2, 3, 4, 5, 6) * c(10, 100) läuft in R ohne Warnung. Heisst das, die Rechnung ist richtig?

Ja, sonst hätte R gewarnt
R warnt nur, wenn die Längen nicht in einem Vielfachen aufgehen. 6 ist ein Vielfaches von 2.
Nein, R wiederholt den kurzen Vektor still, ob das gemeint war oder nicht
Richtig. NumPy würde hier abbrechen. In R schützt nur eine ausdrückliche Kontrolle der Längen.
Nein, R hat das Skalarprodukt gebildet
Es rechnet elementweise mit Wiederholung.

Eine eingelesene Spalte wert hat den Typ character, obwohl sie Zahlen enthält. Was ist die wahrscheinlichste Ursache?

Mindestens ein Eintrag ist kein gültiger Zahlentext, etwa ein Strich für einen fehlenden Wert
Richtig. Ein Vektor trägt nur einen Typ, und ein Texteintrag macht die ganze Spalte zu Text. Abhilfe: na.strings beim Import.
R liest Zahlen aus CSV-Dateien immer als Text
Ohne störenden Eintrag erkennt read.csv Zahlen richtig.
Die Datei hat das falsche Encoding
Das verdirbt Umlaute, macht aber keine Zahlen zu Text.

noten <- factor(c(5, 3, 4)). Was gibt as.numeric(noten) zurück?

5 3 4, die ursprünglichen Werte
Dafür braucht es den Umweg as.numeric(as.character(x)).
3 1 2, die internen Codes
Richtig. Der Faktor speichert die Position in der sortierten Stufenliste 3, 4, 5. Die 5 steht an dritter Stelle.
1 2 3 in der Reihenfolge des Auftretens
Sortiert wird aufsteigend, nicht nach Auftreten.

Ein Skript baut eine Matrix mit matrix(werte, nrow = 2) und wird nach Python als np.array(werte).reshape(2, -1) übertragen. Worauf ist zu achten?

R füllt spaltenweise, NumPy zeilenweise; die Matrizen unterscheiden sich
Richtig. Mit order="F" in NumPy oder byrow = TRUE in R stimmen sie überein. Ohne diese Angabe entsteht kein Fehler, nur eine andere Matrix.
Nichts, beide füllen gleich
Beispiel 6 zeigt die Zeilen 1 3 5 gegen 1 2 3.
-1 ist in NumPy ungültig
-1 heisst “so viele wie nötig” und ist gültig.

Verlinkte Ressourcen