Az R-ben a vector (technikailag atomic vector) azonos type-ú értékek gyűjteménye: leggyakrabban integer, numeric, character vagy logical, ritkábban complex vagy raw.
A memóriában folytonosan tárolódnak, hasonlóan egy C-tömbhöz.
Ha vegyes típusú bemenetet kap, az R csendben mindet egy közös típusra konvertálja, általában character-re, ami váratlan eredményekhez vezethet.
v <- c(2, 5.4, "txt")
v
#> [1] "2" "5.4" "txt"
typeof(v)
#> [1] "character"
Ha már megvan az összes érték, használd a c() függvényt (a „concatenate” rövidítése):
x <- 10
v <- c(4, 7, x)
A c() függvény nagyon rugalmas, a bemenetei között más vektorok és tartományok is szerepelhetnek.
A c() bármennyi és bármilyen bemenetet elfogad, és egyetlen vektorba lapítja őket.
Ha a vektor kicsiként indul, és futásidőben sokat nő (például egy ciklusban adsz hozzá értékeket), sokkal gyorsabb lehet előre lefoglalni egy hosszú vektort, amelyet később valódi adatokkal tölthetsz fel:
v <- vector(length = 100)
Ez minimálisra csökkenti az objektum másolásának szükségességét, ami hosszú vektoroknál lassú és memóriaigényes művelet.
Egymást követő értékek tartományához (növekvő vagy csökkenő) használhatod a : jelölést
v <- 1:5 # equivalent to c(1, 2, 3, 4, 5)
w <- 10:7 # c(10, 9, 8, 7)
Az R-ben a tartomány nem külön típus, csupán egy rövidített módja egy vektor létrehozásának.
A seq() függvény finomabb szabályozást kínál:
# specify step size
seq(2, 11, by = 3) # c(2, 5, 8, 11)
# specify number of values, evenly-spaced
seq(2.5, 4, length.out = 5) # c(2.500, 2.875, 3.250, 3.625, 4.000)
A rep() függvénnyel könnyedén készíthetsz ismétlődő mintázatokat:
count <- 3
rep(7, count)
#> [1] 7 7 7
rep(1:3, count)
#> [1] 1 2 3 1 2 3 1 2 3
rep(1:3, each = 2) # the "each" keyword is required in this case
#> [1] 1 1 2 2 3 3
Néhány tartomány beépített konstansként előre definiálva van:
letters # LETTERS is the UPPERCASE equivalent
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
month.name
#> [1] "January" "February" "March" "April" "May" "June" "July" "August"
#> [9] "September" "October" "November" "December"
month.abb
#> [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
A műveletek automatikusan, elemenként alkalmazódnak a vektorra. A más nyelvekben gyakori ciklusokra, listakomprehenziókra és rekurziókra nincs szükség, és (teljesítmény okokból) lehetőség szerint kerüld is őket.
2 + 1:3 # c(3, 4, 5)
2 * 1:3 # c(2, 4, 6)
12 / 1:3 # c(12 6 4)
2 ^ (1:3) # c(2, 4, 8) : exponentiation, operator precedence order here needs ()
Vektorpárokkal is működik, az elemeket páronként kezelve:
v <- 1:3
w <- 5:7
v + w
#> [1] 6 8 10
v * w
#> [1] 5 12 21
v ^ w
#> [1] 1 64 2187
Ez sokkal erősebb, mint amilyennek elsőre látszik, és a későbbi fogalmakban még sok felfedeznivaló lesz.
Ahogy sok más nyelvben, úgy itt is használhatod a szögletes zárójelbe írt indexet:
v <- 4:7
v[2]
#> [1] 5
v[2:4]
#> [1] 5 6 7
De vigyázz: az R alapértelmezés szerint 1-től indexel. Ez gyakori a tudományos nyelveknél (Fortran, Matlab, Julia), de eltér a C és számos utódjának nullától induló indexelésétől.
Tartományokat is használhatsz, ahogy a fenti példában, de a rendkívül rugalmas c() függvényben is:
v <- c(4, 7, 10)
w <- c(2, v[2:3], 11) # c(2, 7, 10, 11)
A vectors (mint az R-ben a legtöbb dolog) módosíthatónak tekinthető, és ugyanilyen rugalmas szintaxissal írhatsz egyetlen vagy több elemre:
v <- 1:10
v[2] <- 42
v[4:6] <- c(11, 12, 13)
v
#> [1] 1 42 3 11 12 13 7 8 9 10
A más nyelveket jól ismerő programozók esetleg azt gondolhatják, hogy a v[-1] a vektor utolsó eleméhez fér hozzá.
Tévedés!
Erre a tail() függvényt használd.
v <- c(2, 4, 6) # defaults to last 6 entries
tail(v)
#> [1] 2 4 6
tail(v, n=1) # just the last entry
#> [1] 6
A negatív indexek valójában egy elem eltávolítására szolgálnak:
v <- c(2, 4, 6)
v[-2]
#> [1] 2 6 # second element gone
Ez a vektor egy rövidebb másolatát adja vissza. Maga a v változatlan marad.
Ha összehasonlításokat alkalmazol egy vektorra, az ugyanolyan hosszú, Boolean-okból álló vektort ad vissza.
Ez nagyon kényelmes lehet olyan függvényekben, mint az all() és az any():
v <- c(4, 7, 10)
v >= 6
#> [1] FALSE TRUE TRUE
all(v > 6)
#> [1] FALSE # not all elements match this condition
any(v > 6)
#> [1] TRUE # at least one element matches
Bonyolultabb logikai kifejezéseknél fontos, hogy a vektorokon működő & és | operátorokat használd.
A kétszeres karakteres && és || csak egyetlen értékek összehasonlítására való, ahogy arról a [Booleanok][concept-boolean] fogalomban szó volt.
v <- c(4, 7, 10)
v %% 2 == 0 & v > 5
#> [1] FALSE FALSE TRUE
Erre a témára a későbbi fejezetekben még visszatérünk. Egyelőre csak jegyezd meg a konzol kimenetének formátumát:
1:20
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#> [18] 18 19 20
A sorok [ ]-ben álló számokkal kezdődnek, amelyek az első elem indexét jelzik (ez hasznos a több sorba törő hosszú vektoroknál).
De miért előzi meg az [1] az egyetlen értékeket?
Az R-ben nincsenek igazi skalárértékek!
Ami egyetlen számnak vagy betűnek látszik, az valójában egy 1 hosszúságú vektor.
Erre már láttunk utalásokat az Alapok és a Booleanok fogalomban, a numerikus és logikai típusoknál.
A fent leírt vektorokat formálisabban atomic vectors néven ismerjük. Ennek az az oka, hogy csak egyszerű, oszthatatlan (innen az „atomic”) értékeket tartalmazhatnak, például numeric, character, boolean. A bonyolultabb szerkezetek recursive vectors-okat alkothatnak, amelyekről akkor lesz szó, amikor a lists témát tárgyaljuk.