Usuń zduplikowane wiersze


152

Muszę przeczytać CSVplik w data.frame R. Niektóre wiersze mają ten sam element w jednej z kolumn. Chciałbym usunąć wiersze, które są duplikatami w tej kolumnie. Na przykład:

platform_external_dbus          202           16                     google        1
platform_external_dbus          202           16         space-ghost.verbum        1
platform_external_dbus          202           16                  localhost        1
platform_external_dbus          202           16          users.sourceforge        8
platform_external_dbus          202           16                    hughsie        1

Chciałbym tylko jeden z tych wierszy, ponieważ pozostałe mają te same dane w pierwszej kolumnie.


3
Który chcesz? tylko pierwszy? innymi słowy: czy chcesz zachować googleczy localhostczy hughsie?
Anthony Damico,

Nie ma to znaczenia dla tej części mojej analizy statystycznej. Próbuję tylko powiązać tytuł projektu (pierwsza kolumna), liczbę błędów (druga kolumna) i liczbę organizacji w projekcie (trzecia kolumna).
user1897691

3
chłodny. wyrzuć niepotrzebne kolumny i użyj? unikatowego
Anthony Damico

Odpowiedzi:


186

po prostu wyodrębnij ramkę danych do potrzebnych kolumn, a następnie użyj unikalnej funkcji: D

# in the above example, you only need the first three columns
deduped.data <- unique( yourdata[ , 1:3 ] )
# the fourth column no longer 'distinguishes' them, 
# so they're duplicates and thrown out.

1
Wygląda na to, że będzie działać idealnie. Czy możesz mi wyjaśnić, co się dzieje z [,1:3]częścią tego kodu? Jestem nowy w R, dlatego pytam, co, jak mogę tylko założyć, jest oczywistym pytaniem.
user1897691

6
@ user1897691 oznacz to jako poprawne;) obejrzyj to, a jeśli Ci się spodoba, sprawdź twotorials.com
Anthony Damico,

3
Zwróć uwagę, że spowoduje to usunięcie wszystkich kolumn z wyjątkiem trzech pierwszych.
GuillaumeL

186

Dla osób, które przybyły tutaj, aby poszukać ogólnej odpowiedzi na temat usuwania zduplikowanych wierszy, użyj !duplicated():

a <- c(rep("A", 3), rep("B", 3), rep("C",2))
b <- c(1,1,2,4,1,1,2,2)
df <-data.frame(a,b)

duplicated(df)
[1] FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE  TRUE

> df[duplicated(df), ]
  a b
2 A 1
6 B 1
8 C 2

> df[!duplicated(df), ]
  a b
1 A 1
3 A 2
4 B 4
5 B 1
7 C 2

Odpowiedź od: usuwanie zduplikowanych wierszy z ramki danych R.


Chcę utworzyć nową zmienną, która oznacza, że ​​istnieje duplikat danej zmiennej, prawie jak duplikaty df $ <- ifelse (ta wartość wierszy w kolumnie a == poprzednia wartość wiersza w kolumnie a, 1, 0)
jacob


2
To zachowuje pierwszą pojawiającą się wartość i usuwa resztę duplikatów, prawda? Albo losowo usuwa wartości?
News_is_Selection_Bias

@alphabetagamma tak, zachowuje pierwszą wyświetloną wartość
Mehdi Nellen

2
Jeśli interesują Cię tylko duplikaty w niektórych kolumnach, na przykład kolumny 1 i 2, możemy użyćdf[!duplicated(df[, 1:2])]
qwr

82

Funkcja distinct()w dplyrpakiecie wykonuje dowolne usuwanie duplikatów, albo z określonych kolumn / zmiennych (jak w tym pytaniu), albo biorąc pod uwagę wszystkie kolumny / zmienne. dplyrjest częścią tidyverse.

Dane i pakiet

library(dplyr)
dat <- data.frame(a = rep(c(1,2),4), b = rep(LETTERS[1:4],2))

Usuń wiersze zduplikowane w określonej kolumnie (np. Kolumnie a)

Zauważ, że .keep_all = TRUEzachowuje wszystkie kolumny, w przeciwnym razie azachowana zostanie tylko kolumna .

distinct(dat, a, .keep_all = TRUE)

  a b
1 1 A
2 2 B

Usuń wiersze, które są kompletnymi duplikatami innych wierszy:

distinct(dat)

  a b
1 1 A
2 2 B
3 1 C
4 2 D

Świetna odpowiedź, nawiasem mówiąc, .keep_alljest czy zachować wszystkie kolumny, nie należy mieszać z keepw pandas.
Jason Goal

28

data.tablePakiet ma również uniquei duplicatedmetody jej własnego z dodatkowymi funkcjami.

Obie metody unique.data.tablei duplicated.data.tablemetody mają dodatkowy byargument, który umożliwia przekazanie odpowiednio wektora characterlub integerwektora nazw kolumn lub ich lokalizacji

library(data.table)
DT <- data.table(id = c(1,1,1,2,2,2),
                 val = c(10,20,30,10,20,30))

unique(DT, by = "id")
#    id val
# 1:  1  10
# 2:  2  10

duplicated(DT, by = "id")
# [1] FALSE  TRUE  TRUE FALSE  TRUE  TRUE

Inną ważną cechą tych metod jest ogromny wzrost wydajności w przypadku większych zestawów danych

library(microbenchmark)
library(data.table)
set.seed(123)
DF <- as.data.frame(matrix(sample(1e8, 1e5, replace = TRUE), ncol = 10))
DT <- copy(DF)
setDT(DT)

microbenchmark(unique(DF), unique(DT))
# Unit: microseconds
#       expr       min         lq      mean    median        uq       max neval cld
# unique(DF) 44708.230 48981.8445 53062.536 51573.276 52844.591 107032.18   100   b
# unique(DT)   746.855   776.6145  2201.657   864.932   919.489  55986.88   100  a 


microbenchmark(duplicated(DF), duplicated(DT))
# Unit: microseconds
#           expr       min         lq       mean     median        uq        max neval cld
# duplicated(DF) 43786.662 44418.8005 46684.0602 44925.0230 46802.398 109550.170   100   b
# duplicated(DT)   551.982   558.2215   851.0246   639.9795   663.658   5805.243   100  a 

7

Można również użyć dplyr„s distinct()funkcję! Wydaje się, że jest bardziej wydajna niż opcje alternatywne, zwłaszcza jeśli masz mnóstwo obserwacji.

distinct_data <- dplyr::distinct(yourdata)

1
To ta sama odpowiedź, co odpowiedź Sama Firkego, ale z mniejszą ilością szczegółów.
qwr

6

ogólna odpowiedź może brzmieć na przykład:

df <-  data.frame(rbind(c(2,9,6),c(4,6,7),c(4,6,7),c(4,6,7),c(2,9,6))))



new_df <- df[-which(duplicated(df)), ]

wynik:

      X1 X2 X3
    1  2  9  6
    2  4  6  7

1
Zachowaj ostrożność podczas używania -which, jeśli nie ma duplikatów, doprowadzi to do błędu, użycie df[!(duplicated(df)), ]może być bezpieczniejsze.
Jason Goal

5

Z sqldf:

# Example by Mehdi Nellen
a <- c(rep("A", 3), rep("B", 3), rep("C",2))
b <- c(1,1,2,4,1,1,2,2)
df <-data.frame(a,b)

Rozwiązanie:

 library(sqldf)
    sqldf('SELECT DISTINCT * FROM df')

Wynik:

  a b
1 A 1
2 A 2
3 B 4
4 B 1
5 C 2

Ma to narzut związany z konfiguracją całej bazy danych SQL. cran.r-project.org/web/packages/sqldf/index.html
qwr

Co masz na myśli, mówiąc o konfiguracji całej bazy danych SQL? Jest to jedna z głównych zalet: „dzięki sqldf użytkownik nie musi wykonywać następujących czynności, z których wszystkie są wykonywane automatycznie: konfiguracja bazy danych, pisanie instrukcji tworzenia tabeli, która definiuje każdą tabelę, importowanie i eksportowanie do iz bazy danych ”. Nie jest to rozwiązanie optymalne, ale przydatne dla osób znających język SQL.
mpalanco

3

Lub możesz zagnieździć dane w kolumnach 4 i 5 w jednym wierszu za pomocą tidyr:

library(tidyr)
df %>% nest(V4:V5)

# A tibble: 1 × 4
#                      V1    V2    V3             data
#                  <fctr> <int> <int>           <list>
#1 platform_external_dbus   202    16 <tibble [5 × 2]>

Duplikaty kol. 2 i 3 są teraz usuwane do analizy statystycznej, ale dane z kol. 4 i 5 zostały zachowane w tibble i można wrócić do oryginalnej ramki danych w dowolnym momencie za pomocą unnest().


1

Usuń zduplikowane wiersze ramki danych

library(dplyr)
mydata <- mtcars

# Remove duplicate rows of the dataframe
distinct(mydata)

W tym zbiorze danych nie ma ani jednego zduplikowanego wiersza, więc zwrócił on taką samą liczbę wierszy jak w moich danych.



Usuń zduplikowane wiersze na podstawie jednej zmiennej

library(dplyr)
mydata <- mtcars

# Remove duplicate rows of the dataframe using carb variable
distinct(mydata,carb, .keep_all= TRUE)

Funkcja .keep_all służy do zachowania wszystkich innych zmiennych w wyjściowej ramce danych.



Usuń zduplikowane wiersze na podstawie wielu zmiennych

library(dplyr)
mydata <- mtcars

# Remove duplicate rows of the dataframe using cyl and vs variables
distinct(mydata, cyl,vs, .keep_all= TRUE)

Funkcja .keep_all służy do zachowania wszystkich innych zmiennych w wyjściowej ramce danych.

(z: http://www.datasciencemadesimple.com/remove-duplicate-rows-r-using-dplyr-distinct-function/ )


0

Ten problem można również rozwiązać, wybierając pierwszy wiersz z każdej grupy, w której grupa to kolumny, na podstawie których chcemy wybrać unikalne wartości (w przykładzie udostępnionym jest to tylko pierwsza kolumna).

Korzystanie z podstawy R:

subset(df, ave(V2, V1, FUN = seq_along) == 1)

#                      V1  V2 V3     V4 V5
#1 platform_external_dbus 202 16 google  1

W dplyr

library(dplyr)
df %>% group_by(V1) %>% slice(1L)

Lub używając data.table

library(data.table)
setDT(df)[, .SD[1L], by = V1]

Jeśli musimy znaleźć unikalne wiersze na podstawie wielu kolumn, po prostu dodaj te nazwy kolumn w części grupującej dla każdej z powyższych odpowiedzi.

dane

df <- structure(list(V1 = structure(c(1L, 1L, 1L, 1L, 1L), 
.Label = "platform_external_dbus", class = "factor"), 
V2 = c(202L, 202L, 202L, 202L, 202L), V3 = c(16L, 16L, 16L, 
16L, 16L), V4 = structure(c(1L, 4L, 3L, 5L, 2L), .Label = c("google", 
"hughsie", "localhost", "space-ghost.verbum", "users.sourceforge"
), class = "factor"), V5 = c(1L, 1L, 1L, 8L, 1L)), class = "data.frame", 
row.names = c(NA, -5L))

0

Oto bardzo proste, szybkie dplyr/ tidyrozwiązanie:

Usuń wiersze, które są całkowicie takie same:

library(dplyr)
iris %>% 
  distinct(.keep_all = TRUE)

Usuń wiersze, które są takie same tylko w niektórych kolumnach:

iris %>% 
  distinct(Sepal.Length, Sepal.Width, .keep_all = TRUE)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.