Сохранение ПЕРВОЙ уникальной строки каждого блока в кадре данных - PullRequest
0 голосов
/ 12 марта 2020

У меня большой фрейм данных (27 миллионов строк и 18 столбцов). Фрейм данных содержит много дублированных строк, которые я могу удалить, используя, например, отличную от data.table функцию. Однако это дает мне только первую уникальную строку, тогда как я хочу иметь все уникальные строки. Вот воспроизводимый пример:

library(data.table)
library(dplyr)

df<-setNames(data.frame(matrix(ncol = 4, nrow = 10)), c("code", "var1", "var2", "var3"))
df$code<-c("101", "102", "103", "104", "105", "106", "107", "108", "109", "110") 
df$var1<-c(1, 1, 1, 2, 2, 1, 1, 2, 3,3) 
df$var2<-c(1, 1,1, 2, 2, 1,1,2, 3,3 )
df$var3<-c(1, 1,1, 2, 2, 1,1,2, 3,3 )

df<-as.data.table(df)

df<-df %>% distinct(var1, var2, var3, .keep_all=T)

## which gives:
code var1 var2 var3
1:  101    1    1    1
2:  104    2    2    2
3:  109    3    3    3

## however, I want:
  code var1 var2 var3
1  101    1    1    1
2  104    2    2    2
3  106    1    1    1
4  108    2    2    2
5  109    3    3    3

Решение data.table было бы отличным из-за размера исходного кадра данных.

1 Ответ

0 голосов
/ 13 марта 2020

У меня есть решение, использующее data.table, но оно может быть менее оптимальным для вашего набора данных, учитывая его размер, поскольку он создает дополнительные столбцы.

Хотя в вашем примере данные var1, var2 и var3 всегда были то же самое, я собираюсь предположить здесь, что они не должны быть.

library(data.table)
library(zoo) # for rollapplyr function

df<-setNames(data.frame(matrix(ncol = 4, nrow = 10)), c("code", "var1", "var2", "var3"))
df$code<-c("101", "102", "103", "104", "105", "106", "107", "108", "109", "110") 
df$var1<-c(1, 1, 1, 2, 2, 1, 1, 2, 3,3) 
df$var2<-c(1, 1,1, 2, 2, 1,1,2, 3,3 )
df$var3<-c(1, 1,1, 2, 2, 1,1,2, 3,3 )

df <- as.data.table(df) 

Первым шагом является создание переменной, которая показывает, отличается ли переменная в строке i от переменной в строке i-1. Мы делаем это для каждой из трех переменных. Для этого используется функция diff, которая вычисляет разницу в векторе между i и i-1 и применяет ее ко всем столбцам.

df[,dif1 := abs(rollapplyr(var1, 2, function(x){diff(x,lag = 1)}, fill = 1)),]
df[,dif2 := abs(rollapplyr(var2, 2, function(x){diff(x,lag = 1)}, fill = 1)),]
df[,dif3 := abs(rollapplyr(var3, 2, function(x){diff(x,lag = 1)}, fill = 1)),]

Если какая-либо из этих переменных изменилась со строки i-1 тогда это не дубликат Поскольку мы взяли абсолютное значение выброса изменения функцией diff, это означает, что любое значение выше нуля означает изменение. Мы можем взять сумму изменений по трем переменным, а затем отфильтровать те строки, чье изменение больше нуля.

df[,drop := sum(dif1, dif2, dif3), by = code]
df[drop>0, .(code, var1, var2, var3),]

code var1 var2 var3
1:  101    1    1    1
2:  104    2    2    2
3:  106    1    1    1
4:  108    2    2    2
5:  109    3    3    3

Опять же, не уверен, насколько быстро это будет. Я запустил это на 1e4 рядах, и это заняло 0,829 se c, и снова на 1e6 строках, и это заняло 51.118 se c, так что, похоже, все в порядке.

...