Операция R-матрицы

У меня есть матрица (15000 х 3000). Цель состоит в том, чтобы сгенерировать новую матрицу в соответствии с исходной матрицей и начальными значениями. Например, критерии, которые я хотел бы реализовать, таковы:

Вот как мой код настроен на данный момент.

DF1[1,]=1

for( i in 2:2000 ) {
    for( j in 1:15000 ) {

              if(DF[j,i] == 1 && DF1[j-1,i] == 0)
                DF1[j,i] = 1
              else if(DF[j,i] == 0 && DF1[j-1,i] == 1)
                DF1[j,i] = 0
              else DF[j,i,1] = DF1[j-1,i]

    }
}

DF — исходная матрица.

DF1 — новообразованная матрица

Мой вопрос: Есть ли другой способ сделать это? Более быстрый способ?

Так как вложенные циклы плохо работают, я пытаюсь использовать apply, но не знаю, как написать функцию, потому что она связана с двумя матрицами.


Пример

x <- structure(c(1L, 0L, 0L, NA, NA, 0L, NA, 0L, 1L, 0L, 1L, 0L, 0L, 
NA, 0L, NA, 1L, NA, 1L, 0L, 1L, 0L, 1L, 0L), .Dim = c(4L, 6L), .Dimnames = list(
    NULL, NULL))
x
#     [,1] [,2] [,3] [,4] [,5] [,6]
#[1,]    1   NA    1    0    1    1
#[2,]    0    0    0   NA   NA    0
#[3,]    0   NA    1    0    1    1
#[4,]   NA    0    0   NA    0    0

И петля (которая не работает)

for( i in 1:4 ) { 
     for( j in 2:4 ) { 
         if(x[j,i] == 1 && y[j-1,i] == 0) { 
            y[j,i] = 1 
         }else{
            if(x[j,i] == 0 && y[j-1,i] == 1) {
               y[j,i] = 0 
         }else{ 
            y[j,i] = y[j-1,i]
         }
     }
   }

person winnie    schedule 26.12.2015    source источник
comment
DF[j,i,1] 3-мерный?   -  person jogo    schedule 26.12.2015
comment
НЕТ, должно быть DF[j,i]   -  person winnie    schedule 26.12.2015
comment
winnie, было бы здорово, если бы вы добавили небольшой пример с входной матрицей и ожидаемым результатом. Спасибо   -  person user20650    schedule 26.12.2015
comment
Спасибо за пример. Можете ли вы проверить, правильно ли я скопировал его на ваш вопрос. Обратите внимание, что я изменил индекс y[j,i,1] на y[j,i] - это правильно??   -  person user20650    schedule 26.12.2015
comment
Какое сообщение об ошибке вы получаете? В коде, который вы показали для x и y, отсутствует } в конце. Вы не инициализировали y. Матрица x содержит NA; вы не можете проверить равенство с числом. Каким должно быть y, если в x есть запись NA? Вы должны использовать встроенный is.na.   -  person Bhas    schedule 26.12.2015
comment
Не могли бы вы отредактировать свой вопрос, чтобы он начинался с образцов x и y, а также матрицы, которую вы ожидаете получить? Только после этого переходите к описанию того, что вы пробовали и почему вы думаете, что это не удалось. Прямо сейчас я нахожу ваш вопрос слишком сложным - не потому, что проблема сложна, а потому, что трудно понять, что именно является проблемой.   -  person Mirek Długosz    schedule 26.12.2015
comment
да, это должно быть y[j,i]. но вы забыли матрицу Y.y [,1] [,2] [,3] [,4] [,5] [,6] [1,] 0 0 0 0 0 0 [2,] NA NA NA NA NA NA [3,] NA NA NA NA NA NA [4,] NA NA NA NA NA NA, я пытаюсь присвоить значения Y с помощью вложенных циклов, но x, y большие матрицы в моей исходной задаче, интересно, существуют ли другие ответы, спасибо.   -  person winnie    schedule 27.12.2015


Ответы (1)


Функция f1 использует вложенные циклы. (Чтобы избавиться от проблемы, заключающейся в том, что сравнение с NA приводит к нелогическому значению NA, я заменил NA на Inf.) Внимательное прочтение алгоритма, представленного циклами, приводит к альтернативе f2:

f1 <- function( x, initialValues = 1 )
{
  x[which(is.na(x))] <- Inf
  y <- matrix(NA,nrow(x),ncol(x))
  y[1,] <- initialValues

  for( i in 1:ncol(x) ) { 
    for( j in 2:nrow(x) ) { 
      if(x[j,i] == 1 && y[j-1,i] == 0) { 
        y[j,i] = 1 
      }else{
        if(x[j,i] == 0 && y[j-1,i] == 1) {
          y[j,i] = 0 
        }else{ 
          y[j,i] = y[j-1,i]
        }
      }
    }
  }
  return(y)
}

f2 <- function( x, initialValues = 1 )
{  
  g <- function(v)
  {
    m <- cumsum(!is.na(v))
    v[which(!is.na(v))[m]]
  }

  x[which(!(x %in% 0:1))] <- NA
  x[1,] <- initialValues
  return( apply(x,2,g) )
}

Функция g заполняет NA пробелов в векторе v: g(v)[i] равно v[j], где j — наибольший индекс, такой что j<=i и v[j]!=NA. (Доказательство по индукции: v[which(!is.na(v))] содержит не-NA значения в v. Если v[i]==NA, то m[i]==m[i-1] и g(v)[i]==v[which(!is.na(v))[m[i]]]==v[which(!is.na(v))[m[i-1]]==g(v)[i-1]. В противном случае m[i]==m[i-1]+1, следовательно, g(v)[i-1]==v[which(!is.na(v))[m[i-1]]]==v[which(!is.na(v))][m[i-1]] и g(v)[i]==v[which(!is.na(v))[m[i]]]==v[which(!is.na(v))][m[i]]==v[which(!is.na(v))][m[i-1]+1], следующее не-NA значение.)

f2 быстрее, чем f1, особенно для больших матриц. Малая матрица из вопроса:

> library(microbenchmark)

> x <- structure(c(1L, 0L, 0L, NA, NA, 0L, NA, 0L, 1L, 0L, 1L, 0L, 0L, 
+                  NA, 0L, NA, 1L, NA, 1L, 0L, 1L, 0L, 1L, 0L), .Dim = c(4L, 6 .... [TRUNCATED] 

> microbenchmark( f1(x), f2(x) )
Unit: microseconds
  expr     min       lq     mean   median      uq     max neval
 f1(x) 433.864 461.2645 482.9120 471.6805 480.059 920.716   100
 f2(x) 379.518 387.6700 402.9235 391.7465 414.617 620.453   100

> all(f1(x)==f2(x))
[1] TRUE

Большая матрица:

> set.seed(1)

> n <- 200

> m <- 300

> big_x <- matrix(sample(0:10,n*m,replace=TRUE),n,m)

> big_x[sample(1:(n*m),floor((n*m)/3))] <- NA

> microbenchmark( f1(big_x), f2(big_x) )
Unit: milliseconds
      expr       min        lq      mean    median        uq      max neval
 f1(big_x) 360.42174 495.63713 662.54576 772.42981 778.18100 890.0092   100
 f2(big_x)  33.54202  38.65849  62.25661  67.82429  72.42288 188.2729   100

> all(f1(big_x)==f2(big_x))
[1] TRUE
> 

Еще крупнее:

> set.seed(1)

> n <- 800

> m <- 1000

> huge_x <- matrix(sample(0:10,n*m,replace=TRUE),n,m)

> huge_x[sample(1:(n*m),floor((n*m)/3))] <- NA

> microbenchmark( f1(huge_x), f2(huge_x) )
Unit: milliseconds
       expr       min        lq     mean    median       uq       max neval
 f1(huge_x) 4002.4121 7759.2438 8149.821 8466.4698 8950.172 10087.251   100
 f2(huge_x)  311.4259  520.5374  751.874  774.2699 1010.188  1228.504   100

> all(f1(huge_x)==f2(huge_x))
[1] TRUE
> 

Матрица размером 15000 раз 3000, упомянутая в вопросе:

> set.seed(1)

> n <- 15000

> m <- 3000

> x_15k.3k <- matrix(sample(0:1,n*m,replace=TRUE),n,m)

> x_15k.3k[sample(1:(n*m),floor((n*m)/3))] <- NA

> microbenchmark( f1(x_15k.3k), f2(x_15k.3k), times=1 )
Unit: seconds
         expr       min        lq      mean    median        uq       max
 f1(x_15k.3k) 389.47262 389.47262 389.47262 389.47262 389.47262 389.47262
 f2(x_15k.3k)  19.97606  19.97606  19.97606  19.97606  19.97606  19.97606
 neval
     1
     1

> all(f1(x_15k.3k)==f2(x_15k.3k))
[1] TRUE
> 
person mra68    schedule 27.12.2015
comment
ты такой умный !!! Спасибо за ваши восторженные ответы. Но мне немного сложно понять ваш алгоритм, en, так как я новичок в R, не могли бы вы порекомендовать мне книгу для изучения основных алгоритмов (китайский лучше, я не силен в английском)? буду вам очень признателен. - person winnie; 28.12.2015
comment
Извините, но я не знаю такой книги. Я дополнил свой ответ объяснением функции g. Кроме того, я включил возможность выбирать произвольные значения для первой строки. Они не должны быть все 1. - person mra68; 28.12.2015
comment
да, я также заметил, что результат не связан с начальным значением. - person winnie; 28.12.2015