2016-06-16 3 views
3

Я хотел бы добавить столбец-столбец в фрейм данных на основе набора одинаковых строк. Для этого я использовал пакет data.table. В моем случае сравнение строк должно выполняться из комбинации столбцов «z» AND («x» ИЛИ «y»).data.table: «групповой счетчик» для определенной комбинации столбцов

Я проверил:

DF[ , Index := .GRP, by = c("x","y","z") ] 

но результат является сочетание "Z" И "х" и "у".

Как я могу сочетать «z» AND («x» ИЛИ «y»)?

Вот пример данных:

DF = data.frame(x=c("a","a","a","b","c","d","e","f","f"), y=c(1,3,2,8,8,4,4,6,0), z=c("M","M","M","F","F","M","M","F","F")) 
DF <- data.table(DF) 

Я хотел бы иметь этот выход:

> DF 
    x y z Index 
1: a 1 M 1 
2: a 3 M 1 
3: a 2 M 1 
4: b 8 F 2 
5: c 8 F 2 
6: d 4 M 3 
7: e 4 M 3 
8: f 6 F 4 
9: f 0 F 4 
+2

FYI, вы можете создать свой набор данных, используя 'data.table', не используя' data.frame'. Или, альтернативно, конвертируйте свой 'data.frame' в' data.table' без копий, используя 'setDT'. Кроме того, какой должен быть желаемый результат для таких случаев, как 'data.table (x = c (" a "," a "," a "), y = c (1, 1, 2), z = c (" M "," F "," F "))'? –

+1

Для вашего примера 'DF [, Index: = rleid (z)]' будет работать, но он учитывает только «Z», а не («x» ИЛИ «y»). – lmo

+3

Ок, и выход для 'data.table (x = c (" b "," a "," a "), y = c (1, 1, 2), z = c (" F "," F "," F "))'? –

ответ

6

Новая группа начинает работать, если значение z меняется или значения, как для xиy изменяются.

Попробуйте этот пример.

require(data.table) 

DF <- data.table(x = c("a","a","a","b","c","d","e","f","f"), 
       y = c(1,3,2,8,8,4,4,6,0), 
       z=c("M","M","M","F","F","M","M","F","F")) 

# The functions to compare if value is not equal with the previous value 
is.not.eq.with.lag <- function(x) c(T, tail(x, -1) != head(x, -1)) 

DF[, x1 := is.not.eq.with.lag(x)] 
DF[, y1 := is.not.eq.with.lag(y)] 
DF[, z1 := is.not.eq.with.lag(z)] 
DF 

DF[, Index := cumsum(z1 | (x1 & y1))] 
DF 
+0

IIUC, будет ли это работать:' pmin (rleid (dt $ x, dt $ y), rleid (dt $ z)) '? – Arun

+0

@Arun Я думаю, что это не сработает во времена, когда в 'z' есть только шаблон, но нет шаблонов ни в' x', ни в 'y', например' DF <- data.table (x = c (" f "," r "), y = c (6, 0), z = c (" F "," F "))' –

+0

@Arun, похоже, работает. – djhurio

0

Я знаю много людей предупреждают о for петли в R, но в данном случае я считаю, что это очень прямой путь подхода к проблеме. Кроме того, результат не растет, поэтому проблемы с производительностью не являются большой проблемой. Подход for цикл будет:

dt$grp <- rep(NA,nrow(dt)) 
    for (i in 1:nrow(dt)){ 
     if (i == 1){ 
      dt$grp[i] = 1 
     } 
     else { 
      if(dt$z[i-1] == dt$z[i] & (dt$x[i-1] == dt$x[i] | dt$y[i-1] == dt$y[i])){ 
      dt$grp[i] = dt$grp[i-1] 
      }else{ 
      dt$grp[i] = dt$grp[i-1] + 1 
      } 
     } 
    } 

Попытка это на ФОС исходной задачи, результат:

DF = data.frame(x=c("a","a","a","b","c","d","e","f","f"), y=c(1,3,2,8,8,4,4,6,0), z=c("M","M","M","F","F","M","M","F","F")) 
dt <- data.table(DF) 
dt$grp <- rep(NA,nrow(dt)) 
for (i in 1:nrow(dt)){ 
    if (i == 1){ 
     dt$grp[i] = 1 
    } 
    else { 
     if(dt$z[i-1] == dt$z[i] & (dt$x[i-1] == dt$x[i] | dt$y[i-1] == dt$y[i])){ 
     dt$grp[i] = dt$grp[i-1] 
     }else{ 
     dt$grp[i] = dt$grp[i-1] + 1 
     } 
    } 
} 
dt 

    x y z grp 
1: a 1 M 1 
2: a 3 M 1 
3: a 2 M 1 
4: b 8 F 2 
5: c 8 F 2 
6: d 4 M 3 
7: e 4 M 3 
8: f 6 F 4 
9: f 0 F 4 

Попытка это на data.table в @ комментарий Франка, дает ожидаемый результат, а также:

dt<-data.table(x = c("b", "a", "a"), y = c(1, 1, 2), z = c("F", "F", "F")) 
dt$grp <- rep(NA,nrow(dt)) 
for (i in 1:nrow(dt)){ 
    if (i == 1){ 
     dt$grp[i] = 1 
    } 
    else { 
     if(dt$z[i-1] == dt$z[i] & (dt$x[i-1] == dt$x[i] | dt$y[i-1] == dt$y[i])){ 
     dt$grp[i] = dt$grp[i-1] 
     }else{ 
     dt$grp[i] = dt$grp[i-1] + 1 
     } 
    } 
} 
dt 

    x y z grp 
1: b 1 F 1 
2: a 1 F 1 
3: a 2 F 1 
0

EDITED TO ADD: Это решение является в некотором роде более подробной версией той, которая защищена djhurio above. Я думаю, что это показывает, что происходит немного больше, поэтому я оставлю это.

Я думаю, что это задача легче сделать, если она немного разбита. В приведенном ниже коде сначала создаются ДВУХ индексы, один для изменений в x (вложенный в z) и один для изменений в y (вложенный в z). Затем мы найдем первую строку из каждого из этих индексов. Принимая кумулятивную сумму случая, когда оба FIRST.x и FIRST.y являются истинными, должны указать желаемый индекс.

library(data.table) 

dt_example <- data.table(x = c("a","a","a","b","c","d","e","f","f"), 
         y = c(1,3,2,8,8,4,4,6,0), 
         z = c("M","M","M","F","F","M","M","F","F")) 

dt_example[,Index_x := .GRP,by = c("z","x")] 
dt_example[,Index_y := .GRP,by = c("z","y")] 

dt_example[,FIRST.x := !duplicated(Index_x)] 
dt_example[,FIRST.y := !duplicated(Index_y)] 

dt_example[,Index := cumsum(FIRST.x & FIRST.y)] 
dt_example 

    x y z Index_x Index_y FIRST.x FIRST.y Index 
1: a 1 M  1  1 TRUE TRUE  1 
2: a 3 M  1  2 FALSE TRUE  1 
3: a 2 M  1  3 FALSE TRUE  1 
4: b 8 F  2  4 TRUE TRUE  2 
5: c 8 F  3  4 TRUE FALSE  2 
6: d 4 M  4  5 TRUE TRUE  3 
7: e 4 M  5  5 TRUE FALSE  3 
8: f 6 F  6  6 TRUE TRUE  4 
9: f 0 F  6  7 FALSE TRUE  4 
0

Этот подход ищет изменения в x & z | y & z. Дополнительные столбцы оставляются в таблице данных. Чтобы показать вычисления.

DF[, c("Ix", "Iy", "Iz", "dx", "dy", "min.change", "Index") := 
    #Create index of values based on consecutive order 
    list(ix <- rleid(x), iy <- rleid(y), iz <- rleid(z), 
      #Determine if combinations of x+z OR y+z change 
      ix1 <- c(0, diff(rleid(ix+iz))), 
      iy1 <- c(0, diff(rleid(iy+iz))), 
      #Either combination is constant (no change)? 
      change <- pmin(ix1, iy1), 
      #New index based on change 
      cumsum(change) + 1 
     )] 

    x y z Ix Iy Iz dx dy min.change Index 
1: a 1 M 1 1 1 0 0   0  1 
2: a 3 M 1 2 1 0 1   0  1 
3: a 2 M 1 3 1 0 1   0  1 
4: b 8 F 2 4 2 1 1   1  2 
5: c 8 F 3 4 2 1 0   0  2 
6: d 4 M 4 5 3 1 1   1  3 
7: e 4 M 5 5 3 1 0   0  3 
8: f 6 F 6 6 4 1 1   1  4 
9: f 0 F 6 7 4 0 1   0  4 
Смежные вопросы