Jakob Richter

Ersetzen in regelmäßigen Abständen, bzw. nach einem Schema

Vielleicht hat dieses Codebeispiel keine große Praxisrelevanz, aber dennoch stolpert man vielleicht mal über die Aufgabe. Hier also ein fiktives Beispiel:
Es liegt eine sehr einfache Reihe an Messdaten vor, von denen wir wissen, dass sie nur Werktags erhoben wurden. In Wochentagen sähe es also so aus:

MO DI MI DO FR MO DI MI DO FR MO DI..

Nach 5 Messungen ist also eine Lücke von 2 Tagen, die leider nicht im Datensatz selbst ist, die wir aber irgendwie füllen wollen – vielleicht mit Daten aus den Wochenendsmessungen.
Ein Ersetz-Schema sieht also wie folgt aus, wobei T angibt, dass wir die Daten aus dem Datensatz nehmen wollen, ein F gibt an, dass der alternative Datensatz zu nutzen ist.

T T T T T F F T T T T T F F T T

Am einfachsten nachzuvollziehen geht es in einer While-Schleife. Hier bereits in einer sehr allgemein nutzbaren Funktion. Es gibt einen Vektor mit den Ursprungsdaten und einen mit den Lückenfüllern und natürlich das Schema, wonach der neue Vektor entstehen soll.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
stretchjoin <- function (dat, rep, schema, recycle=T) {
  i <- 1 #position in dat
  j <- 1 #position in
  s <- 1 #position in schema
  f <- 1 #position in result
  res <- NULL
  fin <- FALSE
  while(!fin){
    if(schema[s]==T){
      res[f] <- dat[i]
      i <- i+1 #go to next item in dat
    }else{
      res[f] <- rep[j]
      j <- j+1 #go to next item in rep
    }
    s <- s+1 #go to next item in schema
    f <- f+1 #go to next item in result
    if(s>length(schema)){
      #if reached end of schema, start over
      s <- 1
    }
    if(j>length(rep) & recycle){
      j <- 1 #if reached end of replacement vector and recycling allowed, start over
    }else if(schema[s]==F & j>length(rep) & !recycle){
      warning("Reached end of repment vector before end of dat. Set recycle=T!")
      fin <- T
    }
    if(i>length(dat) & schema[s]==T){
      #fin if reached end in dat an next item has to be from dat according to the schema
      fin <- T
    }
  }
  return(res)
}
 
#
# Examples
#
 
x <- 1:12
y <- NA
s <- c(T,T,T,T,T,F,F)
stretchjoin(x,y,s,T)
#[1]  1  2  3  4  5 NA NA  6  7  8  9 10 NA NA 11 12
 
x <- 1:15
y <- -(1:4)
stretchjoin(x,y,s,T)
#[1]  1  2  3  4  5 -1 -2  6  7  8  9 10 -3 -4 11 12 13 14 15 -1 -2

Mit den Ergebnissen als Indexvektor kann man dann auch einfach eine neue Matrix erzeugen. Naja ok. Ein wenig tricksen muss man schon:

mat1 <- matrix(runif(20), ncol=2)
mat2 <- matrix(-(1:2),ncol=2, nrow=2)
mat_neu <- rbind(mat1,mat2)
i1 <- stretchjoin(1:nrow(mat1), rep=nrow(mat1)+(1:nrow(mat2)) ,schema=c(T,T,T,F,F),recycle=T)
mat_neu <- mat_neu[i1,]
mat_neu
#        [,1]        [,2]
#  [1,]  0.39263009  0.53411873
#  [2,]  0.72839589  0.52903701
#  [3,]  0.82255067  0.01965311
#  [4,] -1.00000000 -1.00000000
#  [5,] -2.00000000 -2.00000000
#  [6,]  0.05864827  0.18895893
#  [7,]  0.38650819  0.23657343
#  [8,]  0.73526049  0.45979191
#  [9,] -1.00000000 -1.00000000
# [10,] -2.00000000 -2.00000000
# [11,]  0.46804821  0.93976568
# [12,]  0.20527319  0.31220657
# [13,]  0.25728071  0.84647837
# [14,] -1.00000000 -1.00000000
# [15,] -2.00000000 -2.00000000
# [16,]  0.33444153  0.93647087

Ich bin mir sicher, dass es dafür noch eine schönere Lösung gibt. Vor allem ist diese Lösung bei sehr großen Datensätzen vielleicht nicht die schnellste. Klüger ist es sicherlich direkt einen guten Indexvektor zu erzeugen und nicht mit den Daten zu hantieren. Eine solche Variante wird folgen.

Leave a Reply