Zaawansowane programowanie w R

Spis treści

Typy bazowe

Podstawowe informacje o typach bazowych: od najprostszych do S4.

x <- 2
x
typeof( x)

x <- "ala ma kota"
x
typeof( x)

### Logiczne
typeof( TRUE)
mode( TRUE)
class( TRUE)

### Integers
typeof( 2L)
mode( 2L)
class( 2L)

### Double
typeof( 2)
mode( 2)
class( 2)

### Complex
typeof( 2 + 2i)
mode( 2 + 2i)
class( 2 + 2i)

### Character
typeof( "ala ma kota")
mode( "ala ma kota")
class( "ala ma kota")

### List
typeof( list( a = 123,b = "ala ma kota"))
mode( list( a = 123,b = "ala ma kota"))
class( list( a = 123,b = "ala ma kota"))

### Environment
typeof( globalenv())
mode( globalenv())
class( globalenv())

### Closure
typeof( function(){})
mode( function(){})
class( function(){})

### Language
typeof( quote( x <- 2))
mode( quote( x <- 2))
class( quote( x <- 2))

### S4
typeof( setClass( Class = "test", slots = list( value = "numeric"))( value = 5))
mode( setClass( Class = "test", slots = list( value = "numeric"))( value = 5))
class( setClass( Class = "test", slots = list( value = "numeric"))( value = 5))

Podstawowe informacje o funkcjach

Od pustej do przyjmującej funkcje i ....

f1 <- function(){}
f1()

f2 <- function(){
  print( "Hello world")
}
f2()

f3 <- function( x){
  x^2
}
x <- f3( 4)
x

f4 <- function( x, y){
  x^y
}
f4( 2, 4)

f5 <- function( x, y = 1){
  x^y
}
f5( 2)
f5( 2, 4)
f5( x = 2, y = 5)

f6 <- function( x, f, ...){
  plot( x, f( x), ...)
}

f6( seq( -pi, pi, length.out = 100), sin)
f6( seq( -pi, pi, length.out = 100), sin, pch = 20, type = "o", col = "red", fg = "green", main = "Przykładowy wykres")

Środowiska

Konstrukcja

  • tablica przypisań (tablica hashująca)
  • wskaźnik na rodzica (środowisko)
Symbol Wartość
x 2
y "ala ma kota"
f function

Podstawowe środowiska

Podstawowe środowiska

  • puste
  • bazowe
  • globalne

i odpowiadające im funkcje

  • emptyenv()
  • baseenv()
  • globalenv()
  • environment()
emptyenv()
baseenv()
globalenv()
environment()

Drzewo środowisk i widoczność symboli

Typowe funkcje

  • search()
  • searchpaths()
  • parent.env()
rm( x)
x

search()
searchpaths()
parent.env( parent.env( globalenv()))

Zadanie Napisać funkcję przeszukującą środowiska zarówno w wersji standardowej i rekurencyjnej.

listEnvs <- function( envs = list( globalenv())){
  while( !identical( emptyenv(), last( envs))){
    envs <- c( envs, parent.env( last(  envs)))
  }
envs
}

listEnvs()

listEnvsR <- function( envs = list( globalenv())){
  ## warunek stopu
  if( identical( emptyenv(), last( envs))){
    return( envs)
  }
  ## rekurencja
  envs <- c( envs, parent.env( last( envs)))
  listEnvsR( envs)
}

listEnvsR()

Szukanie symboli

Typowe funkcje

  • exists()
  • where()
ls()
exists( "envs")
exists( "plot")
exists( "plot", inherits = FALSE)
exists( "plot", envir = globalenv(), inherits = FALSE)
exists( "plot", envir = baseenv(), inherits = FALSE)
ls( envir = baseenv(), all.names = TRUE)
ls( envir = baseenv(), all.names = FALSE)
ls()
ls( all.names = TRUE)
.x <- "ala ma kota"
.x
x
ls()
ls( all.names = TRUE)
exists( ".x")
exists( ".x", envir = parent.env( globalenv()))

library( pryr)
where( ".x")
where( "plot")
where( "plot", env = baseenv())

"plot" %in% ls( envir = baseenv())
plot <- function( ...){
  length( list( ...))
}

plot( 1, 2, 3, 4)

x <- seq( -pi, pi, length.out = 100)
y <- sin( x)

plot( x, y)
graphics::plot( x, y)
plot.default( x, y)
plot.ts( ts( cumsum( rnorm( 10 * 12)), start = c( 2000, 1), frequency = 12))
graphics:::plot.data.frame( data.frame( x = 1:100, y = cumsum( rnorm( 100))))
listEnvs( list( environment( graphics:::plot.data.frame)))

Zadanie Napisać funkcję szukającą danego symbolu uwzględniając jego typ i z możliwością znalezienia wszystkich symboli (również zasłanianych). Napisać w wersji standardowej i rekurencyjnej.

### Czyszczenie
rm(list = ls())

### Pakiet
library( dplyr)

### Definicja funkcji
myWhere <- function( name, type, e = list( globalenv())){
  ret <- c()
  while( !identical( emptyenv(), last( e))){
    if( exists( name, envir = last( e), inherits = FALSE)){
      if( identical( type, typeof( get( name, envir = last( e))))){
	ret <- c( ret, last( e))
      }
    }
    e <- c( e, parent.env( last( e)))
  }
  ret
}

plot <- 2L

myWhere( "plot", "closure")
myWhere( "plot", "integer")

Praca ze środowiskami

  • Tworzenie new.env(), attr() dla atrybutu name
  • Usuwanie rm(), gc(), gcinfo()
  • Dodawanie elementów quote(), eval(), $, assign()
  • Listowanie elementów i ich wykorzystanie ls, $, get()
  • Kopiowanie i klonowanie środowiska as.environment(), as.list()
### Czyszczenie
rm(list = ls())

### Tworzenie środowiska
e <- new.env()
e
attr( e, "name") <- "moje środowisko"
e

parent.env( e)

ee <- new.env( parent = emptyenv())
parent.env( ee)

eee <- new.env( parent = ee)
parent.env( eee)
parent.env( parent.env( eee))

### Usuwanie środowisk
e
object.size( e)
object.size( eee)
n <- 10^6
x <- data.frame( id = 1:n, rnorm( n))
object.size( x)
e$x <- x
object.size( e)
rm( e)
gc()
gcinfo( verbose = TRUE)
for( i in 1:10){
  x <- data.frame( id = 1:n, rnorm( n))
}
gcinfo( verbose = FALSE)

### Dodawanie elemntów do środowiska i wyjmowanie definicji ze środowiska
rm(list = ls())

e <- new.env()
attr( e, "name") <- "testEnv"
e

ls()
eval( quote( x <- 3), envir = e)
x
e$x

ee <- new.env( parent = emptyenv())
eval( quote( x <- 3), envir = ee)
ee$`<-` <- `<-`
eval( quote( x <- 3), envir = ee)
ee$x
y <- 2
y
`<-`( y, 123)
y

e$x
e$x <- 321
e$x

e$"x" <- 456
e$"x"
e$x

e$`x` <- TRUE
e$x
e$`x`

e[["x"]]
e[["x"]] <- FALSE
e[["x"]]

e[[`x`]]
e[[1]]
e["x"]
e[1]

assign( x = "y", value = 444, envir = e)
e$y
y

e$x
e[["y"]]
get( x = "y", envir = e)
eval( quote( y), envir = e)

x
e$z
parent.env( e)
z <- 123
e$z
eval( quote( z), envir = e)

w <- list()
w
w$x
w$x <- 123
w

ls()
ls( envir = e)
ls( envir = e, all.names = TRUE)
e$.x <- 999
ls( envir = e)
ls( envir = e, all.names = TRUE)

get( x = "x", envir = e)
get( x = "y", envir = e)
get( x = ".x", envir = e)

### Czyszczenie
rm(list = ls())

### Tworzenie środowiska
e <- new.env()
e$x <- 123

ee <- e
ee$x
ee$x <- 321
ee$x
e$x

e
ee
identical( e, ee)

eee <- as.environment( as.list( e))
eee
eee$x
eee$x <- 999
eee$x
e$x

ls( envir = as.environment( search()[2]))

Zadanie Napisać dwie funkcje, których zadaniem jest przyjmowanie wektora liczb i zwracanie jego permutacji. Jedna funkcja jako strukturę danych wykorzystuje wektor a druga środowisko. Wykonać pętlę implementującą \( n \)-krotne złożenie takich funkcji i zmierzyć czas wykonania dla obu implementacji.

  • Proste manipulowanie ścieżką przeszukiwania attach(), detach()
### Czyszczenie
rm(list = ls())

search()
attach( what = list( "system" = "linux"), name = "systemName")
ls( envir = as.environment( search()[2]))
as.environment( search()[2])$system
detach(name = "systemName")
search()

Zadanie Napisać funkcję, która zapamiętuje ile razy została wywołana ale ma również możliwość zresetowania takiego licznika, przy czym przy resecie nie zostawia za sobą śmieci.

### Czyszczenie
rm(list = ls())

remember <- function(){
  if( !exists( x = "rC", inherits = TRUE)){
    x <- 1
  } else {
    x <- x + 1
  }
  print( x)
}

remember()
x <- "ala"
remember()


remember <- function( reset = FALSE){
  if( !"rC" %in% search()){
    attach( what = list( rC = 0), name = "rC", pos = 2)
  }
  e <- as.environment( "rC")
  e$rC <- e$rC + 1
  if( reset){
    detach( name = "rC")
  }
  print( e$rC)
}

search()
remember()
remember( reset = TRUE)

Funkcje

Konstrukcja fukcji

  • typ bazowy
  • argumenty (ang. formals) formals()
  • ciało funkcji (ang. body) body()
  • domknięcie funkcji (ang. closure) environment()
### Czyszczenie
rm(list = ls())

f <- function(){}
f()

formals( f)
typeof( formals( f))
formals( f) <- alist( x = 0)
formals( f)
f
f()
f( x = 123)

typeof( body( f))
body( f) <- quote( print( x^2))
body( f)
f( 2)

environment( f)

NEXT Środowiska związane z funkcją, static scoping. Zastosowania i problemy.

  • środowisko execution
  • środowisko enclosing environment()
  • środowisko binding
  • środowisko calling parent.frame()

Przykład Sprawdzanie środowiska execution i jego rodzica. Sprawdzanie środowiska enclosing. Niezdefiniowane symbole w ramach funkcji i ich wyszukiwanie.

f <- function(){
  e <- environment()
  e
}

f()

f <- function(){
  e <- environment()
  list( "exe" = e, "exe parent" =  parent.env( e))
}

f()

g <- function(){
  print( x)
}

g()
x <- "ala ma kota"
g()
x <- "kot siedzi na płocie"
g()

g <- function(){
  x <- 123
  print( x)
}

g()
x

g <- function(){
  print( x)
}


h <- function(){
  x <- 999
  g()
}

h()

Przykład Definiowanie symboli z wewnątrz funkcji w środowisku enclosing przy pomocy $ i quote() / eval().

Przykład Funkcja definiująca podany symbol w podanym środowisku.

Przykład Funkcja zwracająca środowisko ze zdefiniowanymi zmiennymi (wstęp do modelu obiektowego R6).

Przykład Funkcje zwracające funkcje i retrospektywna redefinicja w środowisku execution.

Przykład Zmiana środowiska enclosing i wykrywanie środowiska calling parent.frame().

Przykład Co robi funkcja <<-? Funkcje zwracające środowiska execution, enclosing i calling.

Przykład Problemy z gubieniem zmiennych i pseudo-dynamic scoping.

Przykład Środowisko jako struktura danych.

Modele obiektowe

Wprowadzenie

Model obiektowy S3

Model obiektowy S4

Model obiektowy R5 (RC)

Model obiektowy R6

Data: 2021-02-21 Sun 00:00

Autor: Michał Ramsza

Created: 2021-03-24 Wed 17:32

Validate