Подтвердить что ты не робот

Как указать/таблицу данных по номерам групп из group_by?

У меня есть tbl_df, где я хочу group_by(u, v) для каждой отдельной целочисленной комбинации, наблюдаемой с помощью (u, v).


EDIT: это было разрешено добавлением group_indices() обратно в dplyr 0.4.0


a) Затем я хочу присвоить каждой отдельной группе некоторую произвольную отличную метку числа = 1,2,3... например комбинация (u, v) == (2,3) может получить метку 1, (1,3) может получить 2 и т.д. Как сделать это с помощью одного mutate(), без трехступенчатого обобщения и самостоятельного присоединения?

dplyr имеет опрятную функцию n(), но это дает количество элементов внутри ее группы, а не общее число группы. В data.table это будет просто называться .GRP.

b) На самом деле я действительно хочу назначить метку string/character ('A', 'B',...). Но нумерация групп целыми числами достаточно хороша, потому что я могу использовать integer_to_label(i), как показано ниже. Разве есть умный способ объединить эти два? Но не потейте эту часть.

set.seed(1234)

# Helper fn for mapping integer 1..26 to character label
integer_to_label <- function(i) { substr("ABCDEFGHIJKLMNOPQRSTUVWXYZ",i,i) }

df <- tbl_df(data.frame(u=sample.int(3,10,replace=T), v=sample.int(4,10,replace=T)))

# Want to label/number each distinct group of unique (u,v) combinations
df %>% group_by(u,v) %>% mutate(label = n()) # WRONG: n() is number of element within its group, not overall number of group

   u v
1  2 3
2  1 3
3  1 2
4  2 3
5  1 2
6  3 3
7  1 3
8  1 2
9  3 1
10 3 4

KLUDGE 1: could do df %>% group_by(u,v) %>% summarize(label = n()) , then self-join
4b9b3361

Ответ 1

Обновленный ответ

get_group_number = function(){
    i = 0
    function(){
        i <<- i+1
        i
    }
}
group_number = get_group_number()
df %>% group_by(u,v) %>% mutate(label = group_number())

Вы также можете рассмотреть следующую немного нечитаемую версию

group_number = (function(){i = 0; function() i <<- i+1 })()
df %>% group_by(u,v) %>% mutate(label = group_number())

с помощью пакета iterators

library(iterators)

counter = icount()
df %>% group_by(u,v) %>% mutate(label = nextElem(counter))

Ответ 2

dplyr имеет функцию group_indices(), которую вы можете использовать следующим образом:

df %>% 
    mutate(label = group_indices(., u, v)) %>% 
    group_by(label) ...

Ответ 3

Другой подход с использованием data.table будет

require(data.table)
setDT(df)[,label:=.GRP, by = c("u", "v")]

что приводит к:

    u v label
 1: 2 1     1
 2: 1 3     2
 3: 2 1     1
 4: 3 4     3
 5: 3 1     4
 6: 1 1     5
 7: 3 2     6
 8: 2 3     7
 9: 3 2     6
10: 3 4     3

Ответ 4

Обновление моего ответа тремя различными способами:

A) Чистое решение не-dplyr с использованием interaction(u,v):

> df$label <- factor(interaction(df$u,df$v, drop=T))
 [1] 1.3 2.3 2.2 2.4 3.2 2.4 1.2 1.2 2.1 2.1
 Levels: 2.1 1.2 2.2 3.2 1.3 2.3 2.4

> match(df$label, levels(df$label)[ rank(unique(df$label)) ] )
 [1] 1 2 3 4 5 4 6 6 7 7

B) Создание более удобной функции быстрого и грязного генератора Randy более компактно:

get_next_integer = function(){
  i = 0
  function(u,v){ i <<- i+1 }
}
get_integer = get_next_integer() 

df %>% group_by(u,v) %>% mutate(label = get_integer())

C) Также здесь используется однострочный ключ с использованием функции-генератора, использующей назначение глобальной переменной из this:

i <- 0
generate_integer <- function() { return(assign('i', i+1, envir = .GlobalEnv)) }

df %>% group_by(u,v) %>% mutate(label = generate_integer())

rm(i)