Как создать последовательный индекс на основе группирующей переменной в кадре данных

r r-faq

17125 просмотра

6 ответа

У меня есть фрейм данных ( all_data), в котором у меня есть список сайтов (от 1 до n) и их оценки, например

  site  score
     1    10
     1    11  
     1    12
     4    10 
     4    11
     4    11
     8    9
     8    8
     8    7

Я хочу создать столбец, который нумерует каждый уровень сайта в числовом порядке, как счетчик. В этом примере сайты (1, 4 и 8) будут иметь соответствующий счетчик от 1 до 3 в столбце «число»:

site  score number
     1    10    1
     1    11    1 
     1    12    1 
     4    10    2
     4    11    2
     4    11    2
     8    9     3
     8    8     3 
     8    7     3

Я уверен, что это должно быть легко решено, но я еще не нашел пути.

Автор: Gab_27 Источник Размещён: 17.05.2019 03:02

Ответы (6)


15 плюса

Решение

Пытаться Data$number <- as.numeric(as.factor(Data$site))

С одной стороны: разница между решением меня и @Chase, с одной стороны, и решением @DWin, с другой, заключается в упорядочении чисел. И то as.factorи другое factorавтоматически сортирует уровни, тогда как в решении @DWin этого не происходит:

Dat <- data.frame(site = rep(c(1,8,4), each = 3), score = runif(9))

Dat$number <- as.numeric(factor(Dat$site))
Dat$sitenum <- match(Dat$site, unique(Dat$site) ) 

дает

> Dat
  site     score number sitenum
1    1 0.7377561      1       1
2    1 0.3131139      1       1
3    1 0.7862290      1       1
4    8 0.4480387      3       2
5    8 0.3873210      3       2
6    8 0.8778102      3       2
7    4 0.6916340      2       3
8    4 0.3033787      2       3
9    4 0.6552808      2       3
Автор: Joris Meys Размещён: 24.05.2011 03:32

11 плюса

Два других варианта:

1) Использование .GRPфункции из data.tableпакета:

library(data.table)
setDT(dat)[, num := .GRP, by = site]

с примером набора данных снизу это приводит к:

> dat
    site      score num
 1:    1 0.14945795   1
 2:    1 0.60035697   1
 3:    1 0.94643075   1
 4:    8 0.68835336   2
 5:    8 0.50553372   2
 6:    8 0.37293624   2
 7:    4 0.33580504   3
 8:    4 0.04825135   3
 9:    4 0.61894754   3
10:    8 0.96144729   2
11:    8 0.65496051   2
12:    8 0.51029199   2

2) Использование group_indicesфункции из dplyr:

dat$num <- group_indices(dat, site)

или когда вы хотите обойти нестандартную оценку:

library(dplyr)
dat %>% 
  mutate(num = group_indices_(dat, .dots = c('site')))

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

   site      score num
1     1 0.42480366   1
2     1 0.98736177   1
3     1 0.35766187   1
4     8 0.06243182   3
5     8 0.55617002   3
6     8 0.20304632   3
7     4 0.90855921   2
8     4 0.25215078   2
9     4 0.44981251   2
10    8 0.60288270   3
11    8 0.46946587   3
12    8 0.44941782   3

Как видно, dplyrдает другой порядок номеров групп.


Если вам нужен другой номер каждый раз, когда меняется группа, есть несколько других вариантов:

1) с основанием R:

# option 1:
dat$num <- cumsum(c(TRUE, head(dat$site, -1) != tail(dat$site, -1)))

# option 2:
x <- rle(dat$site)$lengths
dat$num <- rep(seq_along(x), times=x)

2) с data.tableпакетом:

library(data.table)
setDT(dat)[, num := rleid(site)]

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

> dat
   site      score num
1     1 0.80817855   1
2     1 0.07881334   1
3     1 0.60092828   1
4     8 0.71477988   2
5     8 0.51384565   2
6     8 0.72011650   2
7     4 0.74994627   3
8     4 0.09564052   3
9     4 0.39782587   3
10    8 0.29446540   4
11    8 0.61725367   4
12    8 0.97427413   4

Используемые данные:

dat <- data.frame(site = rep(c(1,8,4,8), each = 3), score = runif(12))
Автор: Jaap Размещён: 26.09.2016 03:43

11 плюса

Это должно быть довольно эффективно и понятно:

Dat$sitenum <- match(Dat$site, unique(Dat$site))  
Автор: 42- Размещён: 24.05.2011 03:38

3 плюса

Вы можете превратить сайт в фактор, а затем вернуть числовые или целочисленные значения этого фактора:

dat <- data.frame(site = rep(c(1,4,8), each = 3), score = runif(9))
dat$number <- as.integer(factor(dat$site))
dat

  site     score number
1    1 0.5305773      1
2    1 0.9367732      1
3    1 0.1831554      1
4    4 0.4068128      2
5    4 0.3438962      2
6    4 0.8123883      2
7    8 0.9122846      3
8    8 0.2949260      3
9    8 0.6771526      3
Автор: Chase Размещён: 24.05.2011 03:35

1 плюс

Еще одно решение с использованием data.tableпакета.

Пример с более полным набором данных, предоставленным Jaap:

setDT(dat)[, number := frank(site, ties.method = "dense")]
dat
    site     score number
 1:    1 0.3107920      1
 2:    1 0.3640102      1
 3:    1 0.1715318      1
 4:    8 0.7247535      3
 5:    8 0.1263025      3
 6:    8 0.4657868      3
 7:    4 0.6915818      2
 8:    4 0.3558270      2
 9:    4 0.3376173      2
10:    8 0.7934963      3
11:    8 0.9641918      3
12:    8 0.9832120      3
Автор: sindri_baldur Размещён: 21.06.2018 11:11

0 плюса

Используя данные из @Jaap, можно использовать другую dplyrвозможность dense_rank():

dat %>%
 mutate(ID = dense_rank(site))

   site     score ID
1     1 0.1884490  1
2     1 0.1087422  1
3     1 0.7438149  1
4     8 0.1150771  3
5     8 0.9978203  3
6     8 0.7781222  3
7     4 0.4081830  2
8     4 0.2782333  2
9     4 0.9566959  2
10    8 0.2545320  3
11    8 0.1201062  3
12    8 0.5449901  3

Или rleid()подобный подход, с данными, расположенными сначала:

dat %>%
 arrange(site) %>%
 mutate(ID = {ID_rleid = rle(site); rep(seq_along(ID_rleid$lengths), ID_rleid$lengths)})

   site     score ID
1     1 0.1884490  1
2     1 0.1087422  1
3     1 0.7438149  1
4     4 0.4081830  2
5     4 0.2782333  2
6     4 0.9566959  2
7     8 0.1150771  3
8     8 0.9978203  3
9     8 0.7781222  3
10    8 0.2545320  3
11    8 0.1201062  3
12    8 0.5449901  3
Автор: tmfmnk Размещён: 21.02.2019 07:43
Вопросы из категории :
32x32