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

В R я хочу классифицировать каждую строку фрейма данных, разбивая значения по бинам и используя число (сумму) значений в каждом бине, чтобы назначить их в 2 группы (классы) с использованием логики if-else.

  • В цикле R for я использовал команды R cut и split для сортировки значений по строкам.
  • Бины (диапазоны): 1..9, 10 ..19, 20..29, 30..39, 40..49.
  • Если строка содержит 1 пару значений, попадающих в один и тот же интервал (диапазон), скажем, 10..19, то это должно бытьклассифицируется как "P".Если он содержит 2 пары, попадающие в 2 разных бина (диапазона), то их следует классифицировать как «PP».
  • Затем я создал 2 новые переменные с именами p и pp, используя жестко закодированные условия / правила.Значения в переменных - ИСТИНА или ЛОЖЬ, в зависимости от того, соответствует ли n-ая строка этим правилам.
  • Наконец, я использовал p и pp в качестве условий в операторе if-else, чтобы присвоить каждой строке либокласс P (1-я строка) или класс PP (2-я строка).

Сначала я создал фрейм данных x:

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

1-ую строку следует классифицировать как "P ", потому что он имеет 1 пару значений (1, 2), попадающих в одну и ту же ячейку 1..10.
2-й ряд следует классифицировать как" PP ", поскольку он имеет 2 пары значений (11, 14и 32, 37), попадающие в 2 корзины: 10..19 и 30..39 соответственно.

Итак, после создания фрейма данных x я создал цикл for:

for(i in nrow(x)){

# binning the data:
  bins <- split(as.numeric(x[i, ]), cut(as.numeric(x[i, ]), c(0, 9, 19, 29, 39, 49)))
  # creating the rule for p (1 pair of numbers falling in the same range)
  p <- (sum(lengths(bins) == 2) == 1 & sum(lengths(bins) == 1) == 4)
  # creating the rule for pp (2 different pairs, each has 2 numbers falling in the same range)
  pp <- (sum(lengths(bins) == 2) == 2 & sum(lengths(bins) == 1) == 2 & sum(lengths(bins) == 0) == 1)

  if(p){
    x$types <- "P"
  } else if(pp){
    x$types <- "PP"
  } else{
    stop("error")
  }
  }

print(x)

Я хочу создать новый столбец с именем types, содержащий класс P или PP:

  n1 n2 n3 n4 n5 n6 types
1  1  2 10 23 37 45 P
2  7 11 14 32 37 41 PP

Вместо этого код вернул только PP:

  n1 n2 n3 n4 n5 n6 types
1  1  2 10 23 37 45 PP
2  7 11 14 32 37 41 PP

Это потому, что цикл выполняется дважды над строками.Но если он запускается только один раз, все строки классифицируются как «P», а не «PP».Я ожидаю, что это что-то очень простое, просто не смог понять это до сих пор.

Ответы [ 2 ]

0 голосов
/ 04 мая 2019

Ошибка в вашем цикле for в том, что вы не используете i при назначении type. x$types <- "P" присваивает всему столбцу types значение "P". x$types <- "PP" назначает весь столбец types равным "PP". Итак, каким бы ни был последний результат, это будет значение для всего вашего столбца.

Кроме того, использование полной строки x[i, ] опасно после добавления столбца types. Предположительно, вы не хотите пытаться преобразовать значения «P» и «PP» types в числовые значения и скопировать их. Я бы предложил сделать types отдельным вектором и добавить его только в виде столбца после цикла. До цикла: types <- chracter(nrow(x)). Внутри цикла: types[i] <- вместо x$types <-. После цикла x$types <- types.

Вы также делаете классическую синтаксическую ошибку for (i in nrow(x)), когда имеете в виду for (i in 1:nrow(x)).

Исправление всего этого:

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)

types <- character(nrow(x))

for(i in 1:nrow(x)){
  # binning the data:
  bins <- split(as.numeric(x[i, ]), cut(as.numeric(x[i, ]), c(0, 9, 19, 29, 39, 49)))
  # creating the rule for p (1 pair of numbers falling in the same range)
  p <- (sum(lengths(bins) == 2) == 1 & sum(lengths(bins) == 1) == 4)
  # creating the rule for pp (2 different pairs, each has 2 numbers falling in the same range)
  pp <- (sum(lengths(bins) == 2) == 2 & sum(lengths(bins) == 1) == 2 & sum(lengths(bins) == 0) == 1)

  if(p){
    types[i] <- "P"
  } else if(pp){
    types[i] <- "PP"
  } else{
    stop("error")
  }
}

x$types <- types
x
#   n1 n2 n3 n4 n5 n6 types
# 1  1  2 10 23 37 45     P
# 2  7 11 14 32 37 41    PP
0 голосов
/ 03 мая 2019

Это не красиво

x['types'] <- apply(x, 1, function(a) {stringr::str_replace_all(paste(+(table(floor(a/10)) > 1), collapse=""), c('1'='P','0'=''))})

Распаковка

floor(a/10) преобразуется в bin
table(...) > 1 считает корзины и возвращаетTRUE для тех, что> 1
+(...) преобразует логический TRUE/FALSE в 1/0
paste(..., collapse="") объединяет вектор строк в одну строку без пробелов
str_replace_all(..., c('1'='P', ...)) заменяет все подстроки, используя pattern-замены определены как 'old'='new'

Результат

  n1 n2 n3 n4 n5 n6 types
1  1  2 10 23 37 45     P
2  7 11 14 32 37 41    PP
...