Scal ramki danych w R: pełne i częściowe dopasowanie
⚡ Inteligentne podsumowanie
Scalanie ramek danych w R łączy dwie tabele na podstawie jednej lub kilku kolumn klucza współdzielonego. Funkcja merge() obejmuje sprzężenia wewnętrzne, lewe, prawe i pełne, a ten przewodnik demonstruje zarówno dopasowanie pełne, jak i częściowe.

Bardzo często dysponujemy danymi z wielu źródeł. Aby przeprowadzić analizę, musimy to zrobić łączyć dwie ramki danych razem z jedną lub większą liczbą wspólne kluczowe zmienne.
Rodzaje scalania (łączenia) w R
Zanim przejdziemy do przykładów, warto wiedzieć, że merge() wykonuje każdy typ łączenia, jakiego oczekuje użytkownik SQL. Działanie jest kontrolowane przez argumenty all, all.x i all.y, a nie przez inną nazwę funkcji.
| Typ połączenia | Rzędy utrzymane | wywołanie merge() | odpowiednik dplyr |
|---|---|---|---|
| Połączenie wewnętrzne (domyślne) | W obu ramkach znajdują się tylko klucze | scal(x, y, przez = „k”) | inner_join(x, y, by = “k”) |
| Lewe sprzężenie zewnętrzne | Wszystkie wiersze x, NA, gdzie y nie ma dopasowania | scal(x, y, przez = „k”, wszystkie.x = PRAWDA) | left_join(x, y, by = “k”) |
| Prawe połączenie zewnętrzne | Wszystkie wiersze y, NA, gdzie x nie ma dopasowania | scal(x, y, przez = „k”, wszystkie.y = PRAWDA) | right_join(x, y, by = “k”) |
| Pełne połączenie zewnętrzne | Każdy wiersz z obu ramek | merge(x, y, by = „k”, all = TRUE) | pełne_połączenie(x, y, przez = „k”) |
| Połącz krzyżowo | Każda kombinacja rzędów | scal(x, y, przez = NULL) | połączenie_krzyżowe(x, y) |
Przed wykonaniem pierwszej rozmowy warto pamiętać o dwóch szczegółach:
- Pominięcie powoduje, że R scala wszystkie nazwy kolumn, które dzielą dwie ramki, co rzadko jest pożądanym rozwiązaniem.
- merge() sortuje wyniki według kolumny klucza; należy podać wartość sort = FALSE, aby zachować kolejność przychodzącą.
Pełny mecz
Pełne dopasowanie zwraca tylko wartości, które mają odpowiednik w tabeli docelowej. Wiersze bez dopasowania są usuwane z nowej ramki danych. Natomiast częściowe dopasowanie zachowuje te wiersze i wypełnia brakujące kolumny wartościami NA.
Zobaczymy proste połączenie wewnętrzne. Słowo kluczowe internal Join wybiera rekordy, które mają pasujące wartości w obu tabelach. Aby połączyć dwa zbiory danych, możemy użyć funkcji merge(). Użyjemy trzech argumentów:
merge(x, y, by.x = x, by.y = y) Arguments: -x: The origin data frame -y: The data frame to merge -by.x: The column used for merging in x data frame. Column x to merge on -by.y: The column used for merging in y data frame. Column y to merge on
Przykład:
Utwórz pierwszy zbiór danych ze zmiennymi
- nazwisko
- narodowość
Utwórz drugi zbiór danych ze zmiennymi
- nazwisko
- filmy
Wspólną zmienną kluczową jest nazwisko. Możemy połączyć obie ramki danych i sprawdź, czy wymiarowość wynosi 7×3.
Dodajemy stringsAsFactors=FALSE do ramki danych, ponieważ nie chcemy R aby przekonwertować ciągi znaków na czynnik; zmienna powinna pozostać wektorem znaków. Od R 4.0.0 jest to już domyślne ustawienie dla data.frame(), więc argument jest opcjonalny w nowym kodzie i nieszkodliwy w starym kodzie.
# Create origin dataframe( producers <- data.frame( surname = c("Spielberg","Scorsese","Hitchcock","Tarantino","Polanski"), nationality = c("US","US","UK","US","Poland"), stringsAsFactors=FALSE) # Create destination dataframe movies <- data.frame( surname = c("Spielberg", "Scorsese", "Hitchcock", "Hitchcock", "Spielberg", "Tarantino", "Polanski"), title = c("Super 8", "Taxi Driver", "Psycho", "North by Northwest", "Catch Me If You Can", "Reservoir Dogs","Chinatown"), stringsAsFactors=FALSE) # Merge two datasets m1 <- merge(producers, movies, by.x = "surname") m1 dim(m1)
Wyjście:
surname nationality title 1 Hitchcock UK Psycho 2 Hitchcock UK North by Northwest 3 Polanski Poland Chinatown 4 Scorsese US Taxi Driver 5 Spielberg US Super 8 6 Spielberg US Catch Me If You Can 7 Tarantino US Reservoir Dogs
Połączmy ramki danych, gdy wspólne zmienne kluczowe mają różne nazwy.
Zmieniamy nazwisko na imię w ramce danych filmów. Używamy funkcji identycznej(x1, x2), aby sprawdzić, czy obie ramki danych są identyczne.
# Change name of ` movies ` dataframe colnames(movies)[colnames(movies) == 'surname'] <- 'name' # Merge with different key value m2 <- merge(producers, movies, by.x = "surname", by.y = "name") # Print head of the data head(m2)
Wyjście:
##surname nationality title ## 1 Hitchcock UK Psycho ## 2 Hitchcock UK North by Northwest ## 3 Polanski Poland Chinatown ## 4 Scorsese US Taxi Driver ## 5 Spielberg US Super 8 ## 6 Spielberg US Catch Me If You Can
# Check if data are identical
identical(m1, m2)
Wyjście:
## [1] TRUE
Oznacza to, że operacja scalania jest wykonywana nawet wtedy, gdy nazwy kolumn są różne.
Dopasowanie częściowe
Połączenie wewnętrzne powyżej po cichu usuwa wszystko, co nie ma odpowiednika. Nic dziwnego, że dwie ramki danych nie mają tych samych wspólnych zmiennych kluczowych. W pełne dopasowanie, ramka danych zwraca tylko wiersze znalezione w ramce danych x i y. Z częściowe połączenie, możliwe jest zachowanie wierszy bez pasujących wierszy w drugiej ramce danych. Te wiersze będą miały NA w tych kolumnach, które zwykle są wypełnione wartościami z y. Możemy to zrobić ustawiając all.x= TRUE.
Na przykład, możemy dodać nowego producenta, Lucasa, do ramki danych producenta, bez odniesień do filmu w ramce danych filmów. Jeśli ustawimy all.x=FALSE, R połączy tylko pasujące wartości w obu zbiorach danych. W naszym przypadku producent Lucas nie zostanie dołączony do wyniku, ponieważ brakuje go w jednym zbiorze danych.
Zobaczmy wymiar każdego wyjścia, gdy określimy all.x= TRUE i kiedy tego nie zrobimy.
# Create a new producer add_producer <- c('Lucas', 'US') # Append it to the ` producer` dataframe producers <- rbind(producers, add_producer) # Use a partial merge m3 <-merge(producers, movies, by.x = "surname", by.y = "name", all.x = TRUE) m3
Wyjście:
Poniższy wynik konsoli pokazuje dodatkowy wiersz Lucasa, przy czym NA zastępuje brakujący tytuł filmu.
# Compare the dimension of each data frame
dim(m1)
Wyjście:
## [1] 7 3
dim(m2)
Wyjście:
## [1] 7 3
dim(m3)
Wyjście:
## [1] 8 3
Jak widać, nowa ramka danych ma rozmiar 8×3, w porównaniu z 7×3 dla m1 i m2. R wypełnia kolumnę tytułu wartością NA dla Lucasa, producenta, który nie ma pasującego wiersza w ramce danych filmów.
merge() vs dplyr Joinings w R
Base R rozwiązuje każde połączenie za pomocą jednej funkcji i zestawu flag. dplyr Zamiast tego pakiet przypisuje każdemu dołączeniu własny czasownik, co dla wielu zespołów jest łatwiejsze do odczytania w potoku.
| kryteria | Scalanie bazowe() | dplyr dołącza |
|---|---|---|
| Wybór połączenia | all.x / all.y / wszystkie flagi | Nazwa w czasowniku: left_join(), full_join() |
| Kolejność wierszy | Sortowane według klucza, chyba że sort = FALSE | Kolejność lewej tabeli jest zachowana |
| Prędkość na dużych klatkach | Wolniej | Generalnie szybciej |
| Brak kolumny klucza | Nie udaje się późno lub łączy się z niewłaściwymi kolumnami | Błędy natychmiast |
| Zależności | Baza R, nic do zainstalowania | Wymaga pakietu dplyr |
Dwa połączenia pokazane powyżej można bezpośrednio przetłumaczyć na czasowniki dplyr:
library(dplyr) # Same inner join as merge(producers, movies, by.x = "surname", by.y = "name") m4 <- inner_join(producers, movies, by = c("surname" = "name")) # Same partial merge as all.x = TRUE m5 <- left_join(producers, movies, by = c("surname" = "name"))
Metoda Base merge() jest bezpieczniejszym wyborem w pakiecie, który nie powinien zawierać żadnych zależności. Metoda dplyr jest lepszym wyborem w analizie interaktywnej, gdzie czytelność i szybkość mają większe znaczenie.
Typowe błędy scalania w R i jak je naprawić
Większość problemów ze scalaniem jest sygnalizowana nieoczekiwaną liczbą wierszy, a nie komunikatem o błędzie. Warto więc wyrobić w sobie nawyk sprawdzania dim() po każdym połączeniu.
- Wynik ma więcej wierszy niż oba dane wejściowe. Klucz powtarzający się w obu ramkach tworzy połączenie wiele-do-wielu, a R zwraca każdą kombinację. Przed scaleniem sprawdź klucze za pomocą funkcji table(duplicated(x$k)).
- Wynik jest pusty. Kolumny kluczy zazwyczaj różnią się typem lub jedna z nich zawiera spacje na końcu. Uruchom str() na obu ramkach i wyczyść klucz za pomocą trimws() przed scaleniem.
- Kolumny powracają jako title.x i title.y. Obie klatki zawierają kolumnę niekluczową o tej samej nazwie. Sufiksy passu = c(“_producer”, “_film”), aby pochodzenie było oczywiste.
- Rzędy nie są już w swojej pierwotnej kolejności. Funkcja merge() domyślnie sortuje według klucza. Dodaj parametr sort = FALSE lub użyj jawne sortowanie potem.
- Kluczowe porównanie nie sprawdza się pod względem czynników. Porównuj znaki, a nie poziomy czynników: zawrzyj klucz w as.character() przed scaleniem ramek utworzonych w starszych domyślnych wersjach R.
Gdy to samo scalanie musi być powtarzane, należy je umieścić w funkcja zdefiniowana przez użytkownika więc argumenty nie mogą się zmieniać między przebiegami.

