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.

  • 🔑 Kluczowe kolumny: merge() łączy się na by, lub na by.x i by.y, gdy klucz ma inną nazwę w każdej klatce.
  • 🔗 Pełny mecz: Domyślne łączenie wewnętrzne zachowuje tylko wiersze, których klucz pojawia się w obu ramkach danych.
  • 🧩 Częściowe dopasowanie: Ustawienie all.x = TRUE powoduje zachowanie każdego wiersza pierwszej ramki i wypełnienie luk wartościami NA.
  • 📐 Kontrola wymiarów: Porównaj dim() przed i po scaleniu, aby wychwycić wiersze utracone lub zduplikowane w wyniku połączenia.
  • ⚙️ Dołącz do kontroli: Flagi all, all.x i all.y wybierają zachowanie wewnętrzne, lewe, prawe lub całkowicie zewnętrzne.
  • 🛠️. Nowoczesna alternatywa: dplyr nadaje nazwę każdemu połączeniu za pomocą czasownika i zachowuje oryginalną kolejność wierszy.

Scal ramki danych w R

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.

Wyjście konsoli z częściowego scalenia pokazujące Lucasa z NA w kolumnie tytułu

# 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.

FAQ

R scala wszystkie nazwy kolumn, które dzielą obie ramki. W przypadku jednej wspólnej kolumny jest to wygodne; w przypadku kilku po cichu zawęża wynik, a w przypadku braku zwraca sprzężenie krzyżowe. Jawne nadanie klucza pozwala uniknąć wszystkich trzech niespodzianek.

Nie w pojedynczym wywołaniu merge(). Połącz wywołania w łańcuch lub zwiń listę za pomocą Reduce(function(x, y) merge(x, y, by = “k”), list(df1, df2, df3)). Sprawdź liczbę wierszy po każdym kroku, ponieważ duplikaty kluczy szybko się kumulują.

Obie klatki zawierały kolumnę niekluczową o tej samej nazwie, więc R je ujednoznacznia. Przekaż sufiksy = c(“_producer”, “_film”), aby nadać kopiom zrozumiałe nazwy, lub usuń zbędną kolumnę przed scaleniem.

Nie. Funkcja merge() domyślnie sortuje wynik w kolumnie klucza. Wprowadź wartość sort = FALSE, aby zachować kolejność przychodzącą, lub użyj dplyr dołącz, co zachowuje kolejność lewej ramki.

Podaj wektor: merge(x, y, by = c(“surname”, “year”)). Jeśli nazwiska się różnią, przekaż pasujące wektory do by.x i by.y. Oba wektory muszą wymieniać kolumny w tej samej kolejności.

Użyj by = “row.names” lub skróconej wersji by = 0. R dodaje nazwy wierszy z powrotem jako kolumnę o nazwie Row.names, której nazwę zazwyczaj chcesz zmienić lub usunąć przed kontynuowaniem analizy.

Opisz dwie ramki i liczbę wierszy, a asystent AI wskaże zduplikowane klucze jako prawdopodobną przyczynę i zasugeruje sprawdzenie duplicated(). Przed zmianą połączenia potwierdź diagnozę na podstawie własnych danych.

Tak. RStudio W przypadku komputerów stacjonarnych w wersji 2023.09.0 i nowszych dostępna jest opcja opt-in Drugi pilot GitHub Integracja, która tworzy scalanie na podstawie komentarza. Sprawdź wybrany typ łączenia, ponieważ niewłaściwa flaga bezgłośnie zmienia liczbę wierszy.

Podsumuj ten post następująco: