Как назначить уникальный код для повторяющихся строк в этом 'DF' в R? - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть этот фрейм данных df

df <- data.frame(stringsAsFactors=FALSE,
          id = c(1L, 2L, 3L, 4L, 5L, 6L),
     Country = c("ESP", "ESP", "ESP", "ITA", "ITA", "ITA"),
        Year = c(1965L, 1965L, 1965L, 1965L, 1965L, 1965L),
   Time.step = c("Month", "Month", "Month", "Month", "Month", "Month"),
    GSA.numb = c("GSA 5", "GSA 5", "GSA 5", "GSA 17", "GSA 17", "GSA 17"),
     Species = c("Mullus", "Mullus", "Mullus", "Eledone", "Eledone", "Eledone"),
    Quantity = c(500L, 200L, 200L, 350L, 350L, 125L)
                )

df

   id  Country   Year    Time.step    GSA.numb  Species   Quantity
    1    ESP     1965     Month       GSA 5      Mullus     500   
    2    ESP     1965     Month       GSA 5      Mullus     200  
    3    ESP     1965     Month       GSA 5      Mullus     200 
    4    ITA     1965     Month       GSA 17     Eledone    350
    5    ITA     1965     Month       GSA 17     Eledone    350 
    6    ITA     1965     Month       GSA 17     Eledone    125

У меня есть несколько дублированных строк, таких как: 3 и 5. Я могу создать столбец для логического значения F или T, когда строка дублируется:

df$dup <- duplicated(df[,2:7]) #No id! 

результат:

id  Country   Year    Time.step    GSA.numb  Species   Quantity dup
 1    ESP     1965     Month       GSA 5      Mullus     500   FALSE
 2    ESP     1965     Month       GSA 5      Mullus     200   FALSE
 3    ESP     1965     Month       GSA 5      Mullus     200   TRUE
 4    ITA     1965     Month       GSA 17     Eledone    350   FALSE
 5    ITA     1965     Month       GSA 17     Eledone    350   TRUE
 6    ITA     1965     Month       GSA 17     Eledone    125   FALSE

Теперь я хотел бы новый столбец (в динамическом смысле мой истинный df очень большой, со множеством строк, столбцов и переменных)где можно просмотреть количество дублирующихся строк, когда установлено значение ИСТИНА, например:

aspected.df

id  Country Year  Time.step  GSA.numb  Species   Quantity dup  ref  
 1  ESP     1965  Month      GSA 5      Mullus     500   FALSE NA
 2  ESP     1965  Month      GSA 5      Mullus     200   FALSE NA
 3  ESP     1965  Month      GSA 5      Mullus     200   TRUE  =id2
 4  ITA     1965  Month      GSA 17     Eledone    350   FALSE NA
 5  ITA     1965  Month      GSA 17     Eledone    350   TRUE  =id4
 6  ITA     1965  Month      GSA 17     Eledone    125   FALSE NA

Я пытался использовать:

with(df, ave(as.character(Species), df[,2:6], FUN = make.unique)) 

, но результат:

[1] "Mullus"    "Mullus.1"  "Mullus.2"  "Eledone"   "Eledone.1" "Eledone.2"

Я думаю, мне нужно больше ввода кода.Какие функции полезны?(duplicated,make.unit, row.names и тд ...)

Ответы [ 4 ]

0 голосов
/ 20 ноября 2018
Подход

A data.table, начиная с исходного файла:

library(data.table)

setDT(df)[, `:=` (dup = seq_len(.N) > 1, ref = paste0("id", first(id))), 
          by = .(Country, Year, Time.step, GSA.numb, Species, Quantity)][dup == FALSE, ref := NA]

Вывод:

   id Country Year Time.step GSA.numb Species Quantity   dup  ref
1:  1     ESP 1965     Month     GSA5  Mullus      500 FALSE <NA>
2:  2     ESP 1965     Month     GSA5  Mullus      200 FALSE <NA>
3:  3     ESP 1965     Month     GSA5  Mullus      200  TRUE  id2
4:  4     ITA 1965     Month    GSA17 Eledone      350 FALSE <NA>
5:  5     ITA 1965     Month    GSA17 Eledone      350  TRUE  id4
6:  6     ITA 1965     Month    GSA17 Eledone      125 FALSE <NA>

Подход tidyversedup, уже созданным ранее):

library(tidyverse)

df %>% 
  group_by_at(vars(2:7)) %>% 
  mutate(ref = ifelse(dup, paste0("id", first(id)), NA_character_))

Вывод:

     id Country  Year Time.step GSA.numb Species Quantity dup   ref  
  <int> <chr>   <int> <chr>     <chr>    <chr>      <int> <lgl> <chr>
1     1 ESP      1965 Month     GSA5     Mullus       500 FALSE NA   
2     2 ESP      1965 Month     GSA5     Mullus       200 FALSE NA   
3     3 ESP      1965 Month     GSA5     Mullus       200 TRUE  id2  
4     4 ITA      1965 Month     GSA17    Eledone      350 FALSE NA   
5     5 ITA      1965 Month     GSA17    Eledone      350 TRUE  id4  
6     6 ITA      1965 Month     GSA17    Eledone      125 FALSE NA

Если вы хотите создать столбец dup внутри оператора:

df %>% 
  group_by_at(vars(2:7)) %>% 
  mutate(
    dup = row_number() > 1,
    ref = ifelse(dup, paste0("id", first(id)), NA_character_))

Вывод:

     id Country  Year Time.step GSA.numb Species Quantity dup   ref  
  <int> <chr>   <int> <chr>     <chr>    <chr>      <int> <lgl> <chr>
1     1 ESP      1965 Month     GSA5     Mullus       500 FALSE NA   
2     2 ESP      1965 Month     GSA5     Mullus       200 FALSE NA   
3     3 ESP      1965 Month     GSA5     Mullus       200 TRUE  id2  
4     4 ITA      1965 Month     GSA17    Eledone      350 FALSE NA   
5     5 ITA      1965 Month     GSA17    Eledone      350 TRUE  id4  
6     6 ITA      1965 Month     GSA17    Eledone      125 FALSE NA 
0 голосов
/ 20 ноября 2018

В этом примере используется база R и сопоставляется найденные дубликаты с исходным значением.Это полезно, если у вас есть несколько дубликатов для одной строки.

пример данных (используется dput(control = NULL), поэтому символы / коэффициенты были преобразованы в числовые)

df <- data.frame(id = c(1, 1, 1, 2, 2, 2), 
           Country = c(1965, 1965, 1965, 1965, 1965, 1965), 
           Year = c(1, 1, 1, 1, 1, 1), 
           Time.step = c(1, 1, 1, 1, 1, 1), 
           GSA.numb = c(5, 5, 5, 17, 17, 17), 
           Species = c(2, 2, 2, 1, 1, 1), Quantity = c(500, 200, 200, 350, 350, 125))

Код векторизованпоэтому, несмотря на внешний цикл, он должен работать довольно быстро на вашем большом фрейме данных.

df$dup <- duplicated(df)
dupes <- df[df$dup,]
df$ref <- NA # initialize 
for(i in 1:nrow(dupes)){
  z=which(df[,1] == dupes[i,1]&
          df[,2] == dupes[i,2]&
          df[,3] == dupes[i,3]&
          df[,4] == dupes[i,4]&
          df[,5] == dupes[i,5]&
          df[,6] == dupes[i,6]&
          df[,7] == dupes[i,7]) # make sure not to include that $dup column!
  df$ref[z[-1]] <- paste0("=id",min(z))
}
df
#  id Country Year Time.step GSA.numb Species Quantity   dup  ref
#1  1    1965    1         1        5       2      500 FALSE <NA>
#2  1    1965    1         1        5       2      200 FALSE <NA>
#3  1    1965    1         1        5       2      200  TRUE =id2
#4  2    1965    1         1       17       1      350 FALSE <NA>
#5  2    1965    1         1       17       1      350  TRUE =id4
#6  2    1965    1         1       17       1      125 FALSE <NA>

Даже если вы можете усилить это с помощью функций применения, это будет выполняться быстрее.

0 голосов
/ 20 ноября 2018

Использование tidyverse:

df %>%
  group_by_at(vars(-id)) %>% #Group by all variables except of id
  mutate(n = n(), #Identifying the duplicate rows
         dup = ifelse(seq_along(n) > 1, TRUE, FALSE), #Coding the first unique row as TRUE and others as FALSE
         ref = ifelse(dup == TRUE, paste0("=id", first(id[dup == FALSE])), NA_character_)) %>% #Pasting the id of the first unique row
 select(-n)

     id Country  Year Time.step GSA.numb Species Quantity dup   ref  
  <int> <chr>   <int> <chr>     <chr>    <chr>      <int> <lgl> <chr>
1     1 ESP      1965 Month     GSA 5    Mullus       500 FALSE <NA> 
2     2 ESP      1965 Month     GSA 5    Mullus       200 FALSE <NA> 
3     3 ESP      1965 Month     GSA 5    Mullus       200 TRUE  =id2 
4     4 ITA      1965 Month     GSA 17   Eledone      350 FALSE <NA> 
5     5 ITA      1965 Month     GSA 17   Eledone      350 TRUE  =id4 
6     6 ITA      1965 Month     GSA 17   Eledone      125 FALSE <NA> 
0 голосов
/ 20 ноября 2018

Вы можете использовать tidyverse функции для быстрой идентификации дубликатов

df$dup <- duplicated(df[,2:7]) #No id! 

library(tidyverse)

df %>% 
 group_by(dup) %>% 
 mutate(ref=ifelse(dup, paste0("id",1:n()), NA_character_))

#> # A tibble: 6 x 9
#> # Groups:   dup [2]
#>      id Country  Year Time.step GSA.numb Species Quantity dup   ref  
#>   <int> <chr>   <int> <chr>     <chr>    <chr>      <int> <lgl> <chr>
#> 1     1 ESP      1965 Month     GSA 5    Mullus       500 FALSE NA   
#> 2     2 ESP      1965 Month     GSA 5    Mullus       200 FALSE NA   
#> 3     3 ESP      1965 Month     GSA 5    Mullus       200 TRUE  id1  
#> 4     4 ITA      1965 Month     GSA 17   Eledone      350 FALSE NA   
#> 5     5 ITA      1965 Month     GSA 17   Eledone      350 TRUE  id2  
#> 6     6 ITA      1965 Month     GSA 17   Eledone      125 FALSE NA 
...