В R, как добавить столбец с именем «запускается» к фрейму данных, объединяя числовые ячейки в начале каждой строки? - PullRequest
1 голос
/ 24 мая 2019

В R я хочу добавить столбец с именем «start» во фрейм данных, указывающий числовую ячейку в начале каждой строки.Оставшиеся ячейки в той же строке не должны быть включены, что может быть ключом к исправлению приведенного ниже кода.

Значения:

  • единицы (цифры 1-9)быть закодированным как 0
  • десятков (10-19), чтобы быть закодированным как 1
  • двадцатых (20-29), чтобы быть закодированным как 2
  • тридцатых (30-39) должен быть закодирован как 3
  • сорок (40-49), чтобы быть закодирован как 4

Например:

  • Если строка начинается с 3числа в диапазоне 0-9, например: 1 3 5 16 34 43, в столбце стартов должно быть 000, потому что строка начинается с 3 «единиц».
  • Если строка начинается с 12, 16, 32, 42, 45, 47 в столбце стартов должно быть 11;
  • Если строка начинается 32, 36, 30, 42, 45, 48, в столбце стартов должна содержаться строка 333. Я знаючто отдельные функциональные части кода работают сами по себе, моя проблема в том, что я не могу понять, как изменить их, когда они находятся в цикле for с вложенным оператором if-else.Чтобы проверить код, я создал следующий пример фрейма данных:
n1 <- c(1, 7); n2 <- c(2, 11); n3 <- c(10, 14); n4 <- c(23, 32); n5 <- c(37, 37); n6 <- c(45, 41)
x <- data.frame(n1, n2, n3, n4, n5, n6)
x
  n1 n2 n3 n4 n5 n6
1  1  2 10 23 37 45
2  7 11 14 32 37 41
#starts <- character(nrow(x)) # might be helpful to convert to string

for(i in nrow(x)){

  # match the numbers at the start of the row
  ones <- grep("^[0-9]$", x)
  tens <- grep("^[1][0-9]$", x)
  twenties <- grep("^[2][0-9]$", x)
  thirties <- grep("^[3][0-9]$", x)
  forties <- grep("^[4][0-9]$", x)

  # classifying starts
  # using rep() to return 0, 1, 2, 3, 4 times the length of ones, tens, twenties, thirties or forties, respectfully and paste() with collapes="", to paste as string:

  if(any(ones)){
    x[i]$starts <- paste(rep("0", each=length(ones)), collapse="")
  } else if(any(tens)){
    x[i]$starts <- paste(rep("1", each=length(tens)), collapse="")
  } else if(any(twenties)){
    x[i]$starts <- paste(rep("2", each=length(twenties)), collapse="")
  } else if(any(thirties)){
    x[i]$starts <- paste(rep("3", each=length(thirties)), collapse="")
  } else if(any(forties)){
    x[i]$starts <- paste(rep("4", each=length(forties)), collapse="")
  } else(stop("error"))
}

x # print x

Я ожидаю, что результат будет:

 n1 n2 n3 n4 n5 n6 starts
1  1  2 10 23 37 45 00
2  7 11 14 32 37 41 0

Но программа просто печатаетСообщение «Ошибка: ошибка» из последней строки оператора if-else.Я думаю, это потому, что в приведенном выше коде строки с командой grep соответствуют не только числам в начале строки, но и всем оставшимся числам до конца, если регулярное выражение возвращает совпадение.Таким образом, оператор if-else просто переходит к последнему условию else (stop ("error")). Подходы и решения, приведенные ниже, лучше моих, но мне также хотелось бы знать, почему мое решение не работает и может ли оно быть исправлено.

Ответы [ 2 ]

2 голосов
/ 24 мая 2019

Вы можете попробовать что-то вроде этого:

x$starts <- apply(x, 1, function(r) {
  n <- floor(r / 10)
  r <- rle(n)
  paste0(rep(r$values[1], r$lengths[1]), collapse = '')
})

x
##   n1 n2 n3 n4 n5 n6 starts
## 1  1  2 10 23 37 45     00
## 2  7 11 14 32 37 41      0
## 3 21 25 24 29 45 78   2222
## 4 66 67 68 69 69 68 666666
0 голосов
/ 24 мая 2019

Новые данные с более разнообразными результатами:

x<-structure(list(n1 = c(1, 7, 60), n2 = c(2, 11, 62), n3 = c(10, 
  14, 66), n4 = c(23, 32, 67), n5 = c(37, 37, 68), n6 = c(45, 41, 
  69)), row.names = c(NA, -3L), class = "data.frame")

x$starts<-lapply(
                 lapply(strsplit(apply(x,1, function(y) 
                                            paste0(y%/%10,collapse=""))
                                 ,""),
                         rle), 
                  function(a) paste0(rep(a$values[1],a$lengths[1]),collapse=""))

x

  n1 n2 n3 n4 n5 n6 starts
1  1  2 10 23 37 45     00
2  7 11 14 32 37 41      0
3 60 62 66 67 68 69 666666

Я помещаю все это в одну строку, но в основном это вычисляет три полных цифры, а затем только первую цифру принимает столько разкак это повторяется.

Ради интереса я сравнил свой код с @ alko989 в наборе данных длиной ~ 1800 строк.Мой немного быстрее, вероятно, потому что я отказываюсь от использования floor:

Unit: milliseconds
 expr      min       lq    mean   median       uq      max neval
 alko 74.08931 83.40157 99.1486 88.61729 116.0893 166.8620   100
  iod 71.12178 78.14680 94.3105 84.97214 111.4073 156.0593   100
...