v = 1:20) (
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
dim(v)
NULL
length(v)
[1] 20
Vektoren werden in R verwendet, um eindimensionale Daten abzubilden. Häufig sind Daten aber zweidimensional strukturiert, also in Form einer Tabelle. Für tabellarische Daten gibt es in R zwei gängige Datentypen, nämlich Matrizen (Einzahl Matrix) und sogenannte Data Frames. Matrizen können genau wie Vektoren nur Elemente eines einzigen Datentyps enthalten (sie sind also homogene Datentypen). Im Gegensatz dazu können Data Frames Spalten mit unterschiedlichen Datentypen enthalten.
Matrizen sind Vektoren (die wir bereits in der vorigen Einheit kennengelernt haben) mit einem speziellen Dimensionsattribut, welches man mit der Funktion dim()
abfragen und setzen kann:
v = 1:20) (
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
dim(v)
NULL
length(v)
[1] 20
Ein Vektor hat kein Dimensionsattribut, daher wird hier NULL
angezeigt.
Nun kann man für einen Vektor das Dimensionsattribut auf die gewünschte Anzahl an Zeilen und Spalten setzen (das Produkt von Zeilen und Spalten muss mit der Gesamtanzahl an Elementen im Vektor übereinstimmen):
dim(v) = c(4, 5) # 4 Zeilen, 5 Spalten
dim(v)
[1] 4 5
v
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
class(v)
[1] "matrix" "array"
Dieses Beispiel zeigt, dass sich die zugrundeliegenden Daten nicht ändern – sie werden lediglich anders dargestellt bzw. interpretiert.
Mit dem Dimensionsattribut kann man beliebig viele Dimensionen erstellen, nicht nur Matrizen mit zwei Dimensionen. Man spricht dann von Arrays, und eine Matrix ist ein spezielles Array mit zwei Dimensionen.
Eine Matrix kann nicht nur aus einem bereits vorhandenen Vektor, sondern auch direkt mit der Funktion matrix()
erzeugt werden:
m = matrix(1:20, nrow=4, ncol=5)) (
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
Das erste Argument sind die Daten (ein Vektor), die die Matrix enthalten soll. Das zweite Argument nrow
ist die Anzahl der Zeilen, und das dritte Argument ncol
ist die Anzahl der Spalten der Matrix. Wie man sieht werden die ursprünglichen Daten spaltenweise in der Matrix angeordnet. Möchte man die Daten zeilenweise anordnen, kann man das Argument byrow=TRUE
setzen:
matrix(1:20, nrow=4, ncol=5, byrow=TRUE)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 6 7 8 9 10
[3,] 11 12 13 14 15
[4,] 16 17 18 19 20
So wie man einen Vektor mit benannten Elementen erstellen kann, kann man in einer Matrix Zeilen- und Spaltennamen vergeben:
rownames(m) = c("one", "two", "three", "four")
colnames(m) = c("A", "B", "C", "D", "E")
m
A B C D E
one 1 5 9 13 17
two 2 6 10 14 18
three 3 7 11 15 19
four 4 8 12 16 20
Das Herausgreifen einzelner Elemente funktioniert im Prinzip gleich wie bei Vektoren mit eckigen Klammern. Der Hauptunterschied ist, dass man bei Matrizen zwei Indizes angibt: der erste Index entspricht den Zeilen und der zweite entspricht den Spalten. Wenn der erste Index weggelassen wird, werden alle Zeilen herausgegriffen. Wenn der zweite Index weggelassen wird, werden alle Spalten herausgegriffen.
Die folgenden Beispiele illustrieren das:
1, 4] # 1. Zeile, 4. Spalte m[
[1] 13
3] # 3. Spalte m[,
one two three four
9 10 11 12
3,] # 3. Zeile m[
A B C D E
3 7 11 15 19
c(2, 4),] # 2. und 4. Zeile m[
A B C D E
two 2 6 10 14 18
four 4 8 12 16 20
c(1, 3), c(1, 2, 5)] # Zeilen 1 und 3, Spalten 1, 2 und 5 m[
A B E
one 1 5 17
three 3 7 19
"C"] # Spalte C m[,
one two three four
9 10 11 12
"two",] # Zeile "two" m[
A B C D E
2 6 10 14 18
"A"] > 2,] # Zeilen, in denen die Spalte A > 2 ist m[m[,
A B C D E
three 3 7 11 15 19
four 4 8 12 16 20
Wenn man einer numerischen Matrix z.B. eine neue Spalte vom Typ character
hinzufügen möchte, dann funktioniert das nicht wie gewünscht, denn die numerischen Elemente werden automatisch in Zeichenketten umgewandelt (es handelt sich bei einer Matrix ja um einen homogenen Vektor). Wir werden sehen, dass Data Frames besser geeignet sind, wenn man unterschiedliche Spaltentypen benötigt.
= c("Hans", "Birgit", "Ferdinand", "Johanna")
subjects cbind(subjects, m)
subjects A B C D E
one "Hans" "1" "5" "9" "13" "17"
two "Birgit" "2" "6" "10" "14" "18"
three "Ferdinand" "3" "7" "11" "15" "19"
four "Johanna" "4" "8" "12" "16" "20"
Anhand dieses Beispiels sieht man auch eine weitere Möglichkeit, wie man Matrizen erstellen bzw. erweitern kann. Die Funktion cbind()
hängt Vektoren (oder Matrizen) spaltenweise zusammen, während analog dazu die Funktion rbind()
Objekte zeilenweise zusammenfügt.
Genau wie bei Vektoren werden Rechenoperationen mit Matrizen elementweise durchgeführt. Zusätzlich gibt es noch praktische Funktionen, mit denen man die Zeilen- bzw. Spaltensummen einer Matrix berechnen kann, nämlich rowSums()
und colSums()
:
rowSums(m)
one two three four
45 50 55 60
colSums(m)
A B C D E
10 26 42 58 74
Analog dazu gibt es auch noch rowMeans()
bzw. colMeans()
zur Berechnung der Zeilen- bzw. Spaltenmittelwerte.
Eine Matrix ist, wie man anhand der obigen Beispiele erkennt, eigentlich nur für rein numerische Daten geeignet. Oft will man aber auch nicht-numerische Spalten wie z.B. Namen oder Gruppenzugehörigkeiten hinzufügen – dies funktioniert wie oben gezeigt mit Matrizen praktisch nicht, weil dann alle Elemente in den Typ character
konvertiert werden.
Data Frames sind ebenso wie Matrizen zweidimensionale Datenstrukturen (sie bestehen aus Zeilen und Spalten). Im Gegensatz zu Matrizen können Spalten aber unterschiedliche Datentypen beinhalten (z.B. kann eine Spalte numerisch sein, eine andere Spalte kann Zeichenketten beinhalten, und so weiter). Innerhalb einer Spalte müssen aber alle Werte homogen sein. Man kann sich die einzelnen Spalten in einem Data Frame daher als Vektoren vorstellen.
Tatsächlich ist ein Data Frame eine Liste aus Vektoren, welche den einzelnen Spalten entsprechen (den allgemeinen Datentyp list
, welcher hier im Hintergrund verwendet wird, werden wir allerdings nicht genauer kennenlernen).
Mit der Funktion data.frame()
kann man ein Data Frame spaltenweise aus einzelnen Vektoren erzeugen, indem man die einzelnen Spalten als (benannte) Argumente übergibt:
data.frame(x=1:5, id=c("X", "c1", "V", "RR", "7G"), value=c(12, 18, 19, 3, 8))
x id value
1 1 X 12
2 2 c1 18
3 3 V 19
4 4 RR 3
5 5 7G 8
Für die Spaltennamen werden also automatisch die jeweiligen Argumentnamen verwendet, im obigen Beispiel entstehen so die Spaltennamen x
, id
und value
.
Alternativ kann man die Funktion data.frame()
ähnlich wie cbind()
verwenden, um Vektoren und/oder zweidimensionale Objekte (wie Matrizen) spaltenweise aneinanderzuhängen:
df = data.frame(subjects, m)) (
subjects A B C D E
one Hans 1 5 9 13 17
two Birgit 2 6 10 14 18
three Ferdinand 3 7 11 15 19
four Johanna 4 8 12 16 20
Wie bei Matrizen kann man mit der Funktion colnames()
die Spaltennamen lesen bzw. setzen:
colnames(df)
[1] "subjects" "A" "B" "C" "D" "E"
colnames(df) = c("patient", "age", "weight", "bp", "rating", "test")
df
patient age weight bp rating test
one Hans 1 5 9 13 17
two Birgit 2 6 10 14 18
three Ferdinand 3 7 11 15 19
four Johanna 4 8 12 16 20
Erzeugen wir für die folgenden Beispiele nochmals ein kleines Data Frame namens df
(beachten Sie, dass wir in R-Befehlen Zeilenumbrüche zwecks besserer Lesbarkeit einfügen können):
= data.frame(
df patient=c("Hans", "Birgit", "Ferdinand", "Johanna"),
age=c(34, 17, 26, 44),
weight=c(77, 60, 83, 64),
height=c(175, 169, 185, 170)
)
Eine schnelle Übersicht über ein Data Frame bekommt man mit den Funktionen str()
, head()
und tail()
.
Die Funktion str()
stellt die Struktur eines Objektes knapp zusammengefasst dar:
str(df)
'data.frame': 4 obs. of 4 variables:
$ patient: chr "Hans" "Birgit" "Ferdinand" "Johanna"
$ age : num 34 17 26 44
$ weight : num 77 60 83 64
$ height : num 175 169 185 170
Die Funktion head()
gibt die ersten sechs Zeilen am Bildschirm aus, während tail()
die letzten sechs Zeilen ausgibt. Es gibt mit dem Argument n
auch die Möglichkeit, die Anzahl der angezeigten Zeilen anzupassen.
= data.frame(a=rnorm(5000), b=rpois(5000, 2), x=rep(letters, length.out=5000))
l dim(l)
[1] 5000 3
head(l)
a b x
1 0.9443852 1 a
2 0.2546902 1 b
3 1.7179077 2 c
4 0.8916088 4 d
5 -0.5366472 1 e
6 1.0290825 0 f
tail(l, n=4)
a b x
4997 -1.1672707 2 e
4998 0.6468529 3 f
4999 0.2492267 3 g
5000 -0.4431388 3 h
Auf einzelne Spalten eines Data Frames kann man mit $
gefolgt vom Spaltennamen zugreifen (das Ergebnis ist ein Vektor):
$patient df
[1] "Hans" "Birgit" "Ferdinand" "Johanna"
$height df
[1] 175 169 185 170
Diese Schreibweise kann man auch anwenden, wenn man dem Data Frame eine neue Spalte hinzufügen will. Dazu gibt man einen Spaltennamen an, der noch nicht vorhanden ist und weist diesem einen Vektor mit der entsprechenden Länge zu:
$value = c("yes", "no", "no", "yes")
df df
patient age weight height value
1 Hans 34 77 175 yes
2 Birgit 17 60 169 no
3 Ferdinand 26 83 185 no
4 Johanna 44 64 170 yes
Alternativ kann man wie bei Matrizen auch rbind()
bzw. cbind()
zum Hinzufügen neuer Zeilen bzw. Spalten benutzen.
Eine Spalte kann man aus einem Data Frame entfernen, indem man dieser den Wert NULL
zuweist:
$value = NULL
df df
patient age weight height
1 Hans 34 77 175
2 Birgit 17 60 169
3 Ferdinand 26 83 185
4 Johanna 44 64 170
Da ein Data Frame eigentlich eine Liste ist, kann man einzelne Elemente der Liste (welche den Spalten entsprechen), auch mit folgender Syntax herausgreifen:
"patient"]] df[[
[1] "Hans" "Birgit" "Ferdinand" "Johanna"
"height"]] df[[
[1] 175 169 185 170
Dies ist also eine Alternative zur $
-Syntax.
Zeilen und Spalten kann man auch per “normaler” Indizierung mit eckigen Klammern herausgreifen. Dies funktioniert wie bei Vektoren bzw. Matrizen: die erste Zahl in den eckigen Klammern steht für die Zeile und die zweite Zahl für die Spalte. Wenn ein Index weggelassen wird, werden alle Zeilen bzw. Spalten herausgegriffen:
1,] df[
patient age weight height
1 Hans 34 77 175
2:3,] df[
patient age weight height
2 Birgit 17 60 169
3 Ferdinand 26 83 185
Spalten können somit mit dem zweiten Index indiziert werden:
1] df[,
[1] "Hans" "Birgit" "Ferdinand" "Johanna"
4] df[,
[1] 175 169 185 170
Spalten (oder auch Zeilen) kann man anstelle ihrer Indizes auch mit ihren Namen ansprechen:
"patient"] df[,
[1] "Hans" "Birgit" "Ferdinand" "Johanna"
"height"] df[,
[1] 175 169 185 170
Außerdem kann auch gezielt ein bestimmter Bereich herausgegriffen werden, wenn man sowohl Zeilen- als auch Spaltenbereiche angibt:
1:2, c(1, 3:4)] df[
patient weight height
1 Hans 77 175
2 Birgit 60 169
Mit den Bordmitteln von R (d.h. mit den eingebauten Datentypen wie Data Frames sowie dazugehörigen Funktionen) kann man hervorragend arbeiten. Manchmal sind diese Konstrukte aber etwas umständlich zu verwenden, und daher bietet sich die in letzter Zeit immer populärer werdende Paketsammlung namens Tidyverse an, diverse Dinge zu modernisieren bzw. zu vereinfachen. Man installiert alle notwendigen Pakete aus dem Tidyverse mit dem Paket tidyverse
. Darin enthalten ist das Paket tibble
, welches eine moderne Alternative zu Data Frames darstellt. Insbesondere ist die Konvertierung, Erstellung und Indizierung von Tibbles nachvollziehbarer, und die Darstellung von Tibbles am Bildschirm ist wesentlich übersichtlicher. Überall wo man Data Frames verwenden kann, kann man auch Tibbles benutzen.
Bevor man Tibbles verwenden kann, muss man entweder tibble
oder tidyverse
aktivieren. Letzteres aktiviert gleich alle Pakete aus dem Tidyverse.
library(tibble)
Mit der Funktion tibble()
kann man nun ein neues Tibble erstellen, ganz analog zur Funktion data.frame()
:
t = tibble(
(subjects=c("Hans", "Birgit", "Ferdinand", "Johanna"),
A=1:4,
B=5:8,
C=9:12,
D=13:16,
E=17:20
))
# A tibble: 4 × 6
subjects A B C D E
<chr> <int> <int> <int> <int> <int>
1 Hans 1 5 9 13 17
2 Birgit 2 6 10 14 18
3 Ferdinand 3 7 11 15 19
4 Johanna 4 8 12 16 20
Wenn man ein Tibble am Bildschirm ausgibt, werden für jede Spalte automatisch die Datentypen angeführt.
Bei längeren Tabellen zeigt sich ein weiterer Vorteil von Tibbles: gibt man lange Tibbles am Bildschirm aus, wird die Darstellung automatisch so angepasst, dass nicht alle Zeilen/Spalten ausgegeben werden, sondern nur so viel wie möglich um noch einen guten Überblick über die Daten zu gewährleisten. Dies sieht man beispielsweise am Datensatz CO2
, welcher als Data Frame in R vorhanden ist:
CO2
Plant Type Treatment conc uptake
1 Qn1 Quebec nonchilled 95 16.0
2 Qn1 Quebec nonchilled 175 30.4
3 Qn1 Quebec nonchilled 250 34.8
4 Qn1 Quebec nonchilled 350 37.2
5 Qn1 Quebec nonchilled 500 35.3
6 Qn1 Quebec nonchilled 675 39.2
7 Qn1 Quebec nonchilled 1000 39.7
8 Qn2 Quebec nonchilled 95 13.6
9 Qn2 Quebec nonchilled 175 27.3
10 Qn2 Quebec nonchilled 250 37.1
11 Qn2 Quebec nonchilled 350 41.8
12 Qn2 Quebec nonchilled 500 40.6
13 Qn2 Quebec nonchilled 675 41.4
14 Qn2 Quebec nonchilled 1000 44.3
15 Qn3 Quebec nonchilled 95 16.2
16 Qn3 Quebec nonchilled 175 32.4
17 Qn3 Quebec nonchilled 250 40.3
18 Qn3 Quebec nonchilled 350 42.1
19 Qn3 Quebec nonchilled 500 42.9
20 Qn3 Quebec nonchilled 675 43.9
21 Qn3 Quebec nonchilled 1000 45.5
22 Qc1 Quebec chilled 95 14.2
23 Qc1 Quebec chilled 175 24.1
24 Qc1 Quebec chilled 250 30.3
25 Qc1 Quebec chilled 350 34.6
26 Qc1 Quebec chilled 500 32.5
27 Qc1 Quebec chilled 675 35.4
28 Qc1 Quebec chilled 1000 38.7
29 Qc2 Quebec chilled 95 9.3
30 Qc2 Quebec chilled 175 27.3
31 Qc2 Quebec chilled 250 35.0
32 Qc2 Quebec chilled 350 38.8
33 Qc2 Quebec chilled 500 38.6
34 Qc2 Quebec chilled 675 37.5
35 Qc2 Quebec chilled 1000 42.4
36 Qc3 Quebec chilled 95 15.1
37 Qc3 Quebec chilled 175 21.0
38 Qc3 Quebec chilled 250 38.1
39 Qc3 Quebec chilled 350 34.0
40 Qc3 Quebec chilled 500 38.9
41 Qc3 Quebec chilled 675 39.6
42 Qc3 Quebec chilled 1000 41.4
43 Mn1 Mississippi nonchilled 95 10.6
44 Mn1 Mississippi nonchilled 175 19.2
45 Mn1 Mississippi nonchilled 250 26.2
46 Mn1 Mississippi nonchilled 350 30.0
47 Mn1 Mississippi nonchilled 500 30.9
48 Mn1 Mississippi nonchilled 675 32.4
49 Mn1 Mississippi nonchilled 1000 35.5
50 Mn2 Mississippi nonchilled 95 12.0
51 Mn2 Mississippi nonchilled 175 22.0
52 Mn2 Mississippi nonchilled 250 30.6
53 Mn2 Mississippi nonchilled 350 31.8
54 Mn2 Mississippi nonchilled 500 32.4
55 Mn2 Mississippi nonchilled 675 31.1
56 Mn2 Mississippi nonchilled 1000 31.5
57 Mn3 Mississippi nonchilled 95 11.3
58 Mn3 Mississippi nonchilled 175 19.4
59 Mn3 Mississippi nonchilled 250 25.8
60 Mn3 Mississippi nonchilled 350 27.9
61 Mn3 Mississippi nonchilled 500 28.5
62 Mn3 Mississippi nonchilled 675 28.1
63 Mn3 Mississippi nonchilled 1000 27.8
64 Mc1 Mississippi chilled 95 10.5
65 Mc1 Mississippi chilled 175 14.9
66 Mc1 Mississippi chilled 250 18.1
67 Mc1 Mississippi chilled 350 18.9
68 Mc1 Mississippi chilled 500 19.5
69 Mc1 Mississippi chilled 675 22.2
70 Mc1 Mississippi chilled 1000 21.9
71 Mc2 Mississippi chilled 95 7.7
72 Mc2 Mississippi chilled 175 11.4
73 Mc2 Mississippi chilled 250 12.3
74 Mc2 Mississippi chilled 350 13.0
75 Mc2 Mississippi chilled 500 12.5
76 Mc2 Mississippi chilled 675 13.7
77 Mc2 Mississippi chilled 1000 14.4
78 Mc3 Mississippi chilled 95 10.6
79 Mc3 Mississippi chilled 175 18.0
80 Mc3 Mississippi chilled 250 17.9
81 Mc3 Mississippi chilled 350 17.9
82 Mc3 Mississippi chilled 500 17.9
83 Mc3 Mississippi chilled 675 18.9
84 Mc3 Mississippi chilled 1000 19.9
Die Darstellung von allen 84 Zeilen ist wenig übersichtlich, deswegen lässt man sich hier am besten eine Zusammenfassung mittels str()
, head()
oder tail()
ausgeben. Bei Tibbles ist das nicht notwendig, wie wir gleich sehen werden. Die Funktion as_tibble()
konvertiert ein existierendes Data Frame in ein Tibble:
co2_tibble = as_tibble(CO2)) (
# A tibble: 84 × 5
Plant Type Treatment conc uptake
<ord> <fct> <fct> <dbl> <dbl>
1 Qn1 Quebec nonchilled 95 16
2 Qn1 Quebec nonchilled 175 30.4
3 Qn1 Quebec nonchilled 250 34.8
4 Qn1 Quebec nonchilled 350 37.2
5 Qn1 Quebec nonchilled 500 35.3
6 Qn1 Quebec nonchilled 675 39.2
7 Qn1 Quebec nonchilled 1000 39.7
8 Qn2 Quebec nonchilled 95 13.6
9 Qn2 Quebec nonchilled 175 27.3
10 Qn2 Quebec nonchilled 250 37.1
# … with 74 more rows
Man erkennt, dass bei einem Tibble nur die ersten 10 Zeilen dargestellt werden, was wesentlich übersichtlicher ist. Möchte man dennoch alle Zeilen sehen, kann man entweder print()
oder View()
verwenden (welche auch mit Data Frames funktionieren):
print(co2_tibble, n=Inf) # n=Inf zeigt alle Zeilen an
View(co2_tibble) # öffnet eine Tabellenansicht in RStudio
Erstellen Sie einen Vektor u
mit den geraden Zahlen von 98 bis 50 (in absteigender Reihenfolge) und einen Vektor v
mit den geraden Zahlen von 0 bis 48. Wandeln Sie dann beide Vektoren in Matrizen mit jeweils 5 Zeilen um (verwenden Sie dazu dim()
). Fügen Sie anschließend u
und v
(in dieser Reihenfolge) spaltenweise zusammen und speichern Sie das Ergebnis in der Variablen r
ab. Geben Sie dann r
am Bildschirm aus. Welchen Typ hat das Objekt r
?
Beantworten Sie folgende Fragen zur Matrix r
aus Übung 1 mit Hilfe von geeigneten R-Befehlen:
r
?r
insgesamt?Erstellen Sie ein Data Frame (oder Tibble) df
mit 10 Zeilen und 3 Spalten wie folgt:
name
heißen und die Werte Ben, Emma, Luis, Mia, Paul, Hanna, Lukas, Sophia, Jonas und Emilia beinhalten.gender
soll das Geschlecht der Personen beinhalten, d.h. entweder den Buchstaben m
oder f
.value
soll 10 beliebige Zahlen zwischen 1 und 100 beinhalten.Geben Sie abschließend df
am Bildschirm aus. Welche Datentypen haben die drei Spalten?
Erstellen Sie ein neues Data Frame df_f
, welches die Zeilen aller weiblichen Personen aus df
(aus Übung 3) enthält, und geben Sie dieses am Bildschirm aus. Verwenden Sie für die Lösung einen logischen Indexvektor, damit dies auch für beliebig lange Daten (bei denen sich männliche und weibliche Personen nicht zeilenweise abwechseln) funktioniert!
Geben Sie außerdem vier Möglichkeiten an, wie man auf die erste Spalte zugreifen kann!
Erstellen Sie aus dem in R vorhandenen Data Frame mtcars
ein neues Data Frame namens mtcars1
, welches nur aus jenen Zeilen besteht in denen die Spalte mpg
Werte größer als 25 aufweist. Aus wie vielen Zeilen bzw. Spalten bestehen mtcars
bzw. mtcars1
?
Es gibt einen wesentlichen Unterschied zwischen Data Frames und Tibbles beim Indizieren mit normalen eckigen Klammern. Versuchen Sie, diesen Unterschied zu finden, in dem Sie sich den in R verfügbaren Datensatz airquality
ansehen.
Erstellen Sie zunächst ein Tibble namens air
aus dem Data Frame airquality
. Greifen Sie dann aus beiden Objekten die erste Spalte "Ozone"
heraus, und zwar mit folgenden Varianten:
[, 1]
[, "Ozone"]
$Ozone
[["Ozone"]]
Können Sie aus den Ergebnissen eine Regel ableiten, wie das Indizieren bei Data Frames bzw. Tibbles funktioniert und wo die Unterschiede bestehen? Welche Variante ist konsistenter?