Zmienne

Miałaś/eś już okazję trochę posługiwać się zmiennymi, przyszła dobra pora, żeby uporządkować, co już o nich wiemy.

Po pierwsze, co może być w nazwie zmiennej?

W nazwie mogą być litery, cyfry oraz znaki '_' i '.'. Teoretycznie mogą być polskie znaki, ale niekoniecznie w każdej wersji R-a, więc lepiej na wszelki wypadek nie używać, żeby się nie przyzwyczajać bez potrzeby. Mimo, że nazwa może zawierać cyfry i znaki musi się chociaż zacząć literą. Należy też pamiętać, że R rozróżnia duże i małe litery, tj. moja_zmienna to inna nazwa niż Moja_zmienna.

Po drugie, jak warto nazywać zmienne?

Wielu początkujących programistów uważa, że nazwy warto skracać, bo po co takie długie. (Wielu zaawansowanych niestety też.) Nazywają zmienne a, b, c, albo l_zad, sr_oc zamiast liczba_zadan czy srednia_ocen. Nie wiem, czy czas, jaki zaoszczędzili na pisaniu tych nazw jest rzeczywiście wart robienia tego, mam nadzieję, żę chociaż robią z nim coś wartościowego. Zmienne warto nazywać tak, żeby dokładnie wiedzieć, co się pod nimi kryje, i to nie tylko w tej chwili, ale też kiedy za miesiąc zajrzy się do swojego skryptu czy w historię komend. Kiedy wszystkie zmienne są ponazywane po ludzku program można normalnie przeczytać i zrozumieć, o co w nim chodzi; linijka "wydatki = srednia_pensja * liczba_pracownikow" jest zupełnie jasna, linijka "c = a * b" zupełnie nie. Oczywiście obie robią to samo (o ile na odpowiednich zmiennych są te same wartości), ale kiedy po pięciu minutach obliczeń wrócisz parę linijek do góry i będziesz próbował zrozumieć czemu jakiś wynik wychodzi Ci dziwny, ciężko będzie Ci zrozumieć co właściwie siedzi pod zmienną c i skąd się tam wzięło. Dużo łatwiej jest prześledzić własny tok rozumowania z jasno nazwanymi zmiennymi. Jest pewna bardzo cenna zasada: program powinno pisać się w pierwszej kolejności po to, żeby mogło się go wygodnie przeczytać, dopiero w drugiej kolejności żeby działał.

Po trzecie, jak się tworzy zmienną?

To już pojawiało się w poprzednich rozdziałach, ale przypomnę: piszemy nazwę zmiennej, pojedynczy znak równości, a potem wartość, którą chcemy przypisać na zmienną. Wartość nie musi być podana wprost, może to być jakieś skomplikowane wyrażenie, które R dopiero musi obliczyć. W tym miejscu wypada wspomnieć również o drugim sposobie zapisywania wartości na zmienną: za pomocą operatora "<-", oczywiście bez spacji pomiędzy < a -:

> a = 10
> a
[1] 10
> a <- 4 * 2
> a
[1] 8
> a < - "to chyba nie wyjdzie"
Error in -"to chyba nie wyjdzie" : invalid argument to unary operator

Te dwa sposoby przypisania różnią się nieznacznie, ale nie jest to specjalnie istotne. Osobiście używam "=", głównie przez przyzwyczajenie z innych języków programowania. Operator "<-" ma tę ciekawą własność, że można go też zapisać w drugą stronę:

> 3 -> a
> a
[1] 3

I jeszcze jedna pożyteczna rzecz przy tworzeniu zmiennych: jeżeli zapisujemy coś na zmienną, a jednocześnie chcemy, żeby R nam wypisał to na ekran, owo przypisanie możemy wziąć w okrągłe nawiasy:

> ( a = 128 + pi )
[1] 131.1416

Po czwarte, co może być zapisane na zmienną?

Właściwie wszystko. Może to być liczba, TRUE / FALSE (wartość logiczna), wektor, macierz, funkcja, napis...

> zmienna_z_liczba = 4
> jakis_napis = "ala ma kota"
> wektor = c( zmienna_z_liczba, 6, jakis_napis)
> ( zmienna_z_wartoscia_logiczna = 3 > 2 )
[1] TRUE
> zmienna_z_funkcja = sqrt
> zmienna_z_funkcja(9)
[1] 3
> zmienna_z_funkcja(zmienna_z_liczba)
[1] 2
> zmienna_z_funkcja(jakis_napis)
Error in zmienna_z_funkcja(jakis_napis) :
  non-numeric argument to mathematical function

...chciałam tylko sprawdzić, czy dalej umiem zdenerwować R-a. No tak, kazałam mu wykonać funkcję, zapisaną pod zmienną zmienna_z_funkcja, na czymś, co jest zapisane na zmiennej jakis_napis: pod zmienna_z_funkcja kryje się funkcja sqrt, czyli pierwiastek, a pod jakis_napis - napis "ala ma kota". Napisów pierwiastkować się nie da, i w ogóle żadnych "mathematical function" na nich wykonywać, bo są "non-numeric", o czym R mnie uprzejmie informuje.

Po piąte, czy zmienne mogą się zmieniać?

Oczywiście! Po to nazywają się zmienne. Jeśli programowałaś/eś kiedyś w innych językach być może spotkałaś/eś się z tym, że wprawdzie mogą się zmieniać, ale nie mogą zmieniać typów, tj. jeśli raz powiedziałam, że jakis_napis to zmienna trzymająca napis, to nie mogę teraz kazać mu zapisać na nią liczby. No więc w R-ze tak nie jest. Zmienne mogą się zmieniać jak im się żywnie podoba.

> a = 12
> a
[1] 12
> a = 15
> a
[1] 15
>( a = a + 3 )
[1] 18
> a = "a teraz to napis, paczcie"
> a
[1] "a teraz to napis, paczcie"

Coś godnego uwagi dzieje się w poleceniu "a = a + 3": zmieniamy wartość zmiennej a, a jednocześnie używamy tej zmiennej do wyliczenia nowej wartości. Czy to się R-owi nie pomiesza? Skądże - R najpierw obliczy sobie to, co jest z prawej strony, czyli weźmie zmienną a (wtedy wynoszącą 15), doda do niej 3, wyjdzie mu 18, i wtedy ten wynik podstawi pod zmienną a.

Warto wspomnieć, że jeśli na zmienną zapisujemy inną zmienną, R tak naprawdę zapisuje wartość. Na przykład w tym fragmencie kodu:

> a = 10
> b = a

R nie zapamiętuje, że b zawsze ma być równe tyle, co a. Kiedy przypisujemy jakąś wartość na zmienną, R wylicza, co to za wartość (kiedy piszemy a=10 wiele do liczenia nie ma, po prostu wychodzi mu 10) i zapamiętuje ją pod nazwą zmiennej. Jeśli za chwilę każemy mu zapamiętać, że b jest jednak równe 14, zmieni tylko wartość b, a pozostanie nieruszone. Podobnie odwrotnie - jeśli każemy mu teraz zapamiętać, że a jest równe 42, R nie pomyśli "acha, to teraz a to 42, a ponieważ b było warte a, to b teraz też musi być 42". b pozostanie jakie było.

> a
[1] 10
> b
[1] 10
> b = 14
> b
[1] 14
> a
[1] 10
> b = a
> a
[1] 10
> b
[1] 10
> a = 42
> a
[1] 42
> b
[1] 10

Po szóste, co zrobić, jeśli zapomniałam/em, jak nazwałam/em moją zmienną?

Jeżeli pamiętasz chociaż jak zaczyna się jej nazwa, możesz zacząć ją pisać i nacisnąć tabulator; jeśli R zna w tej chwili tylko jedną rzecz, której nazwa się tak zaczyna po prostu uzupełni Ci linię nazwą Twojej zmiennej; jeśli zna kilka, uzupełni tylko tyle, ile jest pewien, a kiedy naciśniesz tabulator jeszcze raz podpowie wszystkie nazwy, które możesz wpisać. Możesz również użyć funkcji "ls()" - po wpisaniu "ls()" R wyświetli wektor z wszystkimi stworzonymi przez Ciebie obiektami. Jeśeli pracujesz w RStudio, możesz też zajrzeć do okna z prawym górnym rogu, gdzie znajdziesz spis wszystkich używanych obecnie zmiennych.

Po siódme, na co jeszcze warto zwracać uwagę nazywając zmienną?

Na to, czy zmienna lub funkcja o takiej nazwie już nie istnieje. I nie chodzi tu tylko o zmienne stworzone przez Ciebie. Przykładowo, w rozdziale o kalkulatorze używaliśmy zmiennej pi - nie musieliśmy wcześniej mówić R-owi, ile ona jest warta, R sam z siebie zna zmienną pi. Jeżeli naszą zmienną nazwiemy pi, stracimy to, co wcześniej było na pi zapisane.

> pi
[1] 3.141593
> pi = 3
> pi
[1] 3

Co ciekawe, nic wielkiego się nie stanie jeśli nazwiemy zmienną nazwą jakiejś funkcji - kiedy będziemy z niej korzystać jak ze zmiennej, R będzie brał jej wartość jako zmiennej, kiedy jak z funkcji - będzie używał funkcji.

> sum    # tu jeszcze sum jest funkcja sumujaca elementy wektora
function (..., na.rm = FALSE)  .Primitive("sum")
> sum + 1     # nie mozna dodawac funkcji i liczby, bedzie error
Error in sum + 1 : non-numeric argument to binary operator
> sum( c(1,2,3) )    # uzywamy sum jako funkcji
[1] 6
> sum = sum( c(1,2,3) )   # a teraz zapisujemy na zmienna sum to co nam wyszlo
> sum    # sum to teraz przede wszystkim zmienna i R wypisze jej wartosc
[1] 6
> sum + 1   # do zmiennej juz mozna dodawac
[1] 7
> sum( c(12,13) )    # ...ale caly czas mozemy tez uzywac sum jako funkcji!
[1] 25

Mimo wszystko nie polecam tego robić. Czasem zdarza się, że chcemy na zmienną zapisać jakąś funkcję. Na przykład mamy kawałek kodu, który wielokrotnie coś robi z liczbami, i do tej pory to coś polegało na dodawaniu ich, ale spodziewamy się, że może któregoś dnia zdecydujemy, że chcielibyśmy wyliczać z nich średnią. Zamiast podmieniać we wszystkich miejscach "sum" na "mean", możemy zrobić na samym początku tak:

> co_robimy_z_liczbami = sum
> # teraz masa komend gdzie robimy to samo z jakimis liczbami
> co_robimy_z_liczbami( c(1, 2, 3, 4) )
[1] 10
> co_robimy_z_liczbami( c(0, pi, 18) )
[1] 21.14159
> co_robimy_z_liczbami( c(13, 17, 42, 1.15) )
[1] 73.15
> # ...

Jeśli teraz stwierdzamy, że jednak chcemy liczyć średnią, a nie sumować, podmieniamy tylko na górze skryptu pierwszą linię na:

> co_robimy_z_liczbami = mean

Wszystkie pozostałe linie zostają takie same, i nagle zamiast sumować zaczynają liczyć średnią. Ale jeśli wcześniej nazwiemy jakąś zmienną sum, to nie zadziała :(

> sum = 4
> co_robimy_z_liczbami = sum
> co_robimy_z_liczbami( c(1, 2, 3, 4) )
Error: could not find function "co_robimy_z_liczbami"

R zapisał sobie, że sum to 4. Wciąż można używać sum jako zwykłej funkcji, bo R swoje własne funkcje pamięta trochę gdzie indziej niż nasze własne zmienne i funkcje. Potem zapisał, że co_robimy_z_liczbami ma być równe sum, czyli 4 (najpierw sięgnął do naszych nazw zmiennych, żeby sprawdzić co to jest sum, nie do swoich funkcji). A potem każemy mu użyć co_robimy_z_liczbami jako funkcji, ale R nie rozumie o co nam chodzi, przecież nie ma takiej funkcji, co_robimy_z_liczbami to tylko nudna zmienna z liczbą.

Jeśli nazywamy zmienne polskimi nazwami jest raczej nieduża szansa, że cokolwiek w R-ze się tak nazywa, ale jeśli używamy nazw angielskich i/lub mocno skróconych takie ryzyko się pojawia. Jeśli mamy wątpliwości czy jakaś funkcja / zmienna już istnieje zawsze warto napisać ją i nacisnąć dwukrotnie tabulator - jeśli będzie wśród podpowiedzi to znaczy, że jest zajęta.

Po ósme, czy R zapamięta moje zmienne na zawsze?

Nie. Jeżeli zrobiłeś/aś zmienną liczba_kosiarek o wartości 23, a potem wyszedłeś/aś z R-a, R powinien zapytać Cię, czy chcesz zachować obszar roboczy (workspace): jeśli odpowiesz y (w terminalu) lub save (w RStudio), w katalogu, w którym R pracował stworzone zostaną ukryte pliki, w których zapisane będą wszystkie komendy, które wykonywałaś/eś, oraz wszystkie zmienne, które stworzyłeś/aś. Przy kolejnym uruchomieniu R-a wszystko to się załaduje i dalej będziesz miał(a) swoją zmienną liczba_kosiarek. Ale jeśli odpowiesz "n" lub "don't save", R oczywiście niczego nie zapisze i przy kolejnym uruchomieniu będzie znał tylko te nazwy, które ma zapisane na stałe, tj. swoje własne zmienne i funkcje.

Uwaga. Pliki z historią i danymi są zapisane w katalogu, w którym R akurat pracuje. Jeśli uruchamiasz R-a w terminalu, jest to po prostu katalog, w którym byłaś/eś, zanim wpisałaś/eś polecenie R. Jeśli uruchamiasz skrypt, będzie to katalog, w którym ów skrypt się znajduje. Zawsze możesz sprawdzić, gdzie R akurat pracuje, wpisując polecenie getwd() (jak get working directory). Jeśi nawet zapisałeś/aś obszar roboczy, ale następnym razem uruchomisz R-a z innego katalogu R nie znajdzie w nim żadnej historii i danych i uruchomi się nie załadowując niczego. Oczywiście to nie znaczy, że Twoje dane przepadły, po prostu musisz uruchomić R-a tak, żeby pracował w katalogu, gdzie są Twoje dane. Możesz też załadować dane i historię komend przy pomocy funkcji load() i loadhistory(), podając w nawiasach ścieżkę do plików z danymi.

> a     # nie ma takiego obiektu, bedzie blad
Error: object 'a' not found
> load("/home/maciosz/katalog_w_ktorym_pracowal_R/.RData")
> a     # teraz juz jest, bo poprzednio go stworzylam, tylko zapisalo sie to w innym katalogu
[1] 10

Jeżeli jakaś zmienna Cię denerwuje, bo zdefiniowałaś/eś ją przez pomyłkę, możesz ją usunąć z pamięci R-a poleceniem rm():

 

> wzorst = 1.53   # ups, literowka, niefajnie
> wzorst
[1] 1.53
> rm(wzorst)
> wzorst
Error: object 'wzorst' not found
> imie = "florek"
> oczy = "niebieskie"
> waga = 66
> wzrost = 154
> ls()
[1] "imie"   "oczy"   "waga"   "wzrost"
> rm(imie, oczy)
> ls()
[1] "waga"   "wzrost"
> rm( list = ls() )
> ls()
character(0)

rm spodziewa się, że dostanie po prostu wypisane nazwy, jeśli są zapakowane w jakąś listę lub wektor (jak to jest w przypadku nazw zwróconych przez funkcję ls()), trzeba mu powiedzieć, że to lista, stąd owo "list = ls()" kiedy chcemy usunąć wszystko. Zauważmy, że przed character(0) nie ma napisu [1], co ma dużo sensu - character(0) to pusty wektor, a nie pierwszy element jakiegoś wektora.

Po dziewiąte, czy dużo jeszcze rzeczy muszę wiedzieć o zmiennych, żeby programować w R-ze?

Nie, to właściwie wszystko :) Zapraszamy do kolejnego rozdziału!