Hướng dẫn sử dụng dplyr trong R: Ghép và nối dữ liệu với ví dụ

⚡ Tóm tắt thông minh

Thư viện dplyr hợp nhất và kết hợp các khung dữ liệu trong R bằng bốn lệnh: left_join(), right_join(), inner_join() và full_join(). Gói đi kèm tidyr sau đó định hình lại kết quả đã kết hợp bằng cách sử dụng gather(), spread(), separate() và unite().

  • 🔗 Biến đổi các phép nối: Hàm left_join() giữ lại mọi hàng của bảng nguồn và hàm right_join() giữ lại mọi hàng của bảng đích.
  • 🎯 Kiểm soát trận đấu: Hàm inner_join() loại bỏ các hàng không khớp, trong khi hàm full_join() giữ lại cả hai phía và điền vào các khoảng trống bằng giá trị NA.
  • 🗝️ Khóa tổng hợp: Truyền tham số = c(“ID”, “year”) bất cứ khi nào một cột đơn không xác định được một hàng một cách duy nhất.
  • 🔄 Reshaping: Hàm `gather()` biến một bảng rộng thành bảng dài và hàm `spread()` biến nó trở lại như cũ, giữ nguyên như vậy.ping Một biến cho mỗi cột.
  • ✂️ Chia rẽ và thống nhất: Hàm separate() tách một cột dựa trên dấu phân cách, còn hàm unite() nối các cột lại thành một cột duy nhất.
  • ⚠️ Ghi chú phiên bản: Các hàm pivot_longer(), pivot_wider() và separate_wider_delim() thay thế cho các hàm tidyr resha cũ hơn.ping chức năng.

Dplyr trong R: Hợp nhất và kết hợp dữ liệu

Giới thiệu về Phân tích Dữ liệu

Trước khi bất kỳ sự tham gia hoặc resha nàoping Động từ này nghe có vẻ hợp lý, giúp ta hiểu rõ hơn việc thao tác dữ liệu phù hợp ở đâu. Phân tích dữ liệu có thể được chia thành ba phần:

  • Extracsản xuất: Đầu tiên, chúng ta cần thu thập dữ liệu từ nhiều nguồn và kết hợp chúng lại.
  • Chuyển đổi: Bước này liên quan đến việc thao tác dữ liệu. Khi chúng tôi đã hợp nhất tất cả các nguồn dữ liệu, chúng tôi có thể bắt đầu làm sạch dữ liệu.
  • Hình dung: Động thái cuối cùng là trực quan hóa dữ liệu của chúng tôi để kiểm tra sự bất thường.

Sơ đồ bên dưới cho thấy ba giai đoạn này liên kết với nhau như thế nào.

Quy trình phân tích dữ liệu ba giai đoạn thể hiện ví dụtracsự chuyển đổi, biến đổi và trực quan hóa
Quy trình phân tích dữ liệu

Một trong những thách thức lớn nhất mà các nhà khoa học dữ liệu phải đối mặt là thao tác dữ liệu. Dữ liệu không bao giờ có sẵn ở định dạng mong muốn. Các nhà khoa học dữ liệu cần dành ít nhất một nửa thời gian để làm sạch và thao tác dữ liệu. Đó là một trong những nhiệm vụ quan trọng nhất trong công việc. Nếu quá trình thao tác dữ liệu không hoàn chỉnh, chính xác và chặt chẽ, mô hình sẽ không hoạt động chính xác.

R dplyr

R có một gói gọi là dplyr dùng để xử lý việc chuyển đổi dữ liệu. Nó được xây dựng dựa trên một tập hợp nhỏ các lệnh cốt lõi — filter(), select(), arrange(), mutate() và summarise() — cùng với một nhóm các hàm kết hợp. Sau khi dữ liệu được định dạng, ggplot2 có thể trực quan hóa nó.

Chúng ta sẽ học cách sử dụng gói dplyr để thao tác với một đối tượng. Khung dữ liệuNếu R chưa được cài đặt, hãy làm theo hướng dẫn sau. Các bước thiết lập R và RStudiosau đó chạy install.packages(“dplyr”).

Ghép dữ liệu bằng dplyr

dplyr cung cấp một cách hay và thuận tiện để kết hợp các tập dữ liệu. Chúng ta có thể có nhiều nguồn dữ liệu đầu vào và đến một lúc nào đó, chúng ta cần kết hợp chúng lại. Kết hợp với dplyr sẽ thêm các biến ở bên phải tập dữ liệu gốc.

dplyr Tham gia

Sau đây là bốn loại phép nối quan trọng được sử dụng trong dplyr để hợp nhất hai tập dữ liệu. Cả bốn đều nhận cùng các đối số — hai bảng và khóa — và chỉ khác nhau ở việc giữ lại những hàng không khớp:

Chức năng Mục tiêu Lập luận Nhiều phím
chỗ nối bên trái() Hợp nhất hai tập dữ liệu. Giữ tất cả các quan sát từ bảng gốc x, y, by = “ID” x, y, by = c(“ID”, “ID2”)
phải_join() Hợp nhất hai tập dữ liệu. Giữ tất cả các quan sát từ bảng đích x, y, by = “ID” x, y, by = c(“ID”, “ID2”)
bên trong_join() Kết hợp hai tập dữ liệu. Loại bỏ tất cả các hàng không khớp. x, y, by = “ID” x, y, by = c(“ID”, “ID2”)
full_join() Kết hợp hai tập dữ liệu. Giữ lại tất cả các quan sát. x, y, by = “ID” x, y, by = c(“ID”, “ID2”)

Bốn động từ này tương ứng với các phép nối TRÁI, PHẢI, TRONG và NGOÀI HOÀN TOÀN của SQL. R cơ bản đạt được kết quả tương tự thông qua các đối số all, all.x và all.y của hợp nhất ().

Chúng ta sẽ nghiên cứu tất cả các loại phép nối thông qua một ví dụ đơn giản.

Trước hết, chúng ta xây dựng hai tập dữ liệu. Bảng 1 chứa hai biến, ID và y, trong khi Bảng 2 thu thập ID và z. Trong mỗi trường hợp, chúng ta cần có một cặp khóa Biến đổi. Trong trường hợp của chúng tôi, ID là của chúng tôi chính biến. Hàm này sẽ tìm kiếm các giá trị giống hệt nhau trong cả hai bảng và gán các giá trị trả về vào bên phải của bảng 1. Hình dưới đây cho thấy hai bảng đặt cạnh nhau.

Hai bảng mẫu có chung cột khóa ID trước khi hợp nhất bằng dplyr.

library(dplyr)
df_primary <- tribble(
  ~ID, ~y,
   "A", 5,
   "B", 5,
   "C", 8,
   "D", 0,
  "F", 9)
df_secondary <- tribble(
  ~ID, ~z,
   "A", 30,
   "B", 21,
   "C", 22,
   "D", 25,
   "E", 29)

dplyr left_join()

Cách phổ biến nhất để hợp nhất hai tập dữ liệu là sử dụng hàm left_join(). Hình ảnh bên dưới cho thấy cặp khóa khớp với các hàng A, B, C và D, trong khi E và F bị bỏ lại. Với left_join(), chúng ta giữ lại tất cả các hàng trong bảng gốc và bỏ qua các hàng không có cặp khóa trong bảng đích. Trong ví dụ của chúng ta, giá trị E không tồn tại trong bảng 1, vì vậy hàng đó bị loại bỏ. Giá trị F đến từ bảng gốc, vì vậy nó được giữ lại sau khi thực hiện left_join() và trả về NA trong cột z.

Ví dụ về dplyr left_join()

Sơ đồ bên dưới mô tả những gì xảy ra trong quá trình thực hiện left_join().

Sơ đồ của hàm dplyr left_join keeping mọi hàng của bảng gốc và xóaping ID E

left_join(df_primary, df_secondary, by ='ID')

Đầu ra:

## 
# A tibble: 5 x 3
##      ID   y.x   y.y
##   <chr> <dbl> <dbl>		
## 1     A     5    30
## 2     B     5    21
## 3     C     8    22
## 4     D     0    25
## 5     F     9    NA

Lưu ý rằng khi cả hai bảng đều có một cột cùng tên, dplyr sẽ phân biệt chúng bằng các hậu tố .x và .y như đã nêu ở trên.

dplyr right_join()

Hàm right_join() hoạt động chính xác như left_join(). Sự khác biệt duy nhất là hàng bị bỏ. Giá trị E có sẵn trong khung dữ liệu đích, tồn tại trong bảng mới và lấy giá trị NA cho cột y.

Ví dụ về dplyr right_join()

Sơ đồ bên dưới thể hiện hình ảnh phản chiếu.

Sơ đồ của hàm dplyr right_join keeping mọi hàng của bảng đích và xóaping Mã số F

right_join(df_primary, df_secondary, by = 'ID')

Đầu ra:

##
# A tibble: 5 x 3
##      ID   y.x   y.y
##   <chr> <dbl> <dbl>
## 1     A     5    30
## 2     B     5    21
## 3     C     8    22
## 4     D     0    25
## 5     E    NA    29

dplyr inner_join()

Khi các quan sát không khớp hoàn toàn vô dụng, chúng ta có thể quay lại. có thể các hàng tồn tại trong cả hai Các tập dữ liệu. Đây là lựa chọn phù hợp khi chúng ta cần một tập dữ liệu hoàn chỉnh và không muốn điền các giá trị thiếu bằng giá trị trung bình hoặc trung vị.

Hàm inner_join() sẽ giúp ích trong trường hợp này. Nó loại bỏ các hàng không khớp ở cả hai phía.

Ví dụ về dplyr Inner_join()

Sơ đồ bên dưới minh họa bốn ID còn lại sau khi kết nối.

Sơ đồ hàm dplyr inner_join chỉ trả về bốn ID có trong cả hai bảng.

inner_join(df_primary, df_secondary, by ='ID')

Đầu ra:

## 
# A tibble: 4 x 3
##      ID   y.x   y.y
##   <chr> <dbl> <dbl>
## 1     A     5    30
## 2     B     5    21
## 3     C     8    22
## 4     D     0    25

dplyr full_join()

Cuối cùng, hàm full_join() giữ lại tất cả các quan sát và thay thế các giá trị thiếu bằng NA.

Ví dụ về dplyr full_join()

Sơ đồ bên dưới hiển thị tất cả các ID từ cả hai bảng còn lại sau phép nối.

Sơ đồ của hàm dplyr full_join keeping tất cả sáu ID và điền các giá trị thiếu bằng NA

full_join(df_primary, df_secondary, by = 'ID')

Đầu ra:

## # A tibble: 6 x 3
##      ID   y.x   y.y
##   <chr> <dbl> <dbl>
## 1     A     5    30
## 2     B     5    21
## 3     C     8    22
## 4     D     0    25
## 5     F     9    NA
## 6     E    NA    29

Nhiều cặp khóa

Cuối cùng nhưng không kém phần quan trọng, chúng ta có thể có nhiều khóa trong tập dữ liệu của mình. Hãy xem xét tập dữ liệu sau đây, trong đó chúng ta có các năm và danh sách các sản phẩm mà khách hàng đã mua. Ảnh chụp màn hình bên dưới hiển thị hai bảng và các cột ID và năm, cùng nhau xác định một hàng.

Hai khung dữ liệu chia sẻ một khóa tổng hợp được tạo từ các cột ID và năm.

Nếu ta chỉ kết hợp hai bảng dựa trên ID, thì mỗi năm sẽ được so khớp với mỗi năm khác và số lượng hàng sẽ tăng lên đáng kể. Để khắc phục tình trạng này, ta có thể truyền hai biến cặp khóa, đó là ID và năm, xuất hiện trong cả hai tập dữ liệu. Ta có thể sử dụng đoạn mã sau để hợp nhất bảng 1 và bảng 2:

df_primary <- tribble(
  ~ID, ~year, ~items,
  "A", 2015,3,
  "A", 2016,7,
  "A", 2017,6,
  "B", 2015,4,
  "B", 2016,8,
  "B", 2017,7,
  "C", 2015,4,
  "C", 2016,6,
  "C", 2017,6)
df_secondary <- tribble(
  ~ID, ~year, ~prices,
  "A", 2015,9,
  "A", 2016,8,
  "A", 2017,12,
  "B", 2015,13,
  "B", 2016,14,
  "B", 2017,6,
  "C", 2015,15,
  "C", 2016,15,
  "C", 2017,13)
left_join(df_primary, df_secondary, by = c('ID', 'year'))

Đầu ra:

## # A tibble: 9 x 4
##      ID  year items prices
##   <chr> <dbl> <dbl>  <dbl>
## 1     A  2015     3      9
## 2     A  2016     7      8
## 3     A  2017     6     12
## 4     B  2015     4     13
## 5     B  2016     8     14
## 6     B  2017     7      6
## 7     C  2015     4     15
## 8     C  2016     6     15
## 9     C  2017     6     13

Từ phiên bản dplyr 1.1.0 (tháng 1 năm 2023), cùng một khóa có thể được viết dưới dạng join_by(ID, year), và dplyr hiện cảnh báo về các kết quả khớp nhiều-nhiều không mong muốn, vì dplyr 1.1.0 tham gia thông báo giải thích.

Chức năng làm sạch dữ liệu trong R

Việc hợp nhất chỉ giải quyết được một nửa vấn đề, vì bảng kết hợp vẫn cần được định dạng lại. Sau đây là bốn hàm quan trọng để làm sạch dữ liệu:

Chức năng Mục tiêu Lập luận
tập trung() Chuyển đổi dữ liệu từ rộng sang dài (dữ liệu, khóa, giá trị, na.rm = FALSE)
lây lan() Chuyển đổi dữ liệu từ dài sang rộng (dữ liệu, khóa, giá trị)
chia() Chia một biến thành hai biến. (data, col, into, sep = “”, remove = TRUE)
đoàn kết() Kết hợp hai biến thành một. (data, col, conc, sep = “”, remove = TRUE)

Ghi chú phiên bản: Các hàm `gather()` và `spread()` đã được thay thế bằng `pivot_longer()` và `pivot_wider()` trong tidyr 1.0.0, và hàm `separate()` được thay thế bằng nhóm hàm `separate_wider_delim()` trong tidyr 1.3.0. Các hàm đã được thay thế vẫn chạy, vì vậy mọi ví dụ bên dưới đều hoạt động, nhưng mã mới nên ưu tiên các nhóm hàm mới hơn được hiển thị trong phần mô tả. hình ảnh xoay gọn gàng.unit() vẫn đang được sử dụng.

Chúng tôi sử dụng gói tidyr, một phần của bộ sưu tập tidyverse, để thao tác, làm sạch và trực quan hóa dữ liệu. Nếu R được cài đặt cùng với Anaconda, gói này đã có sẵn từ đó. https://anaconda.org/r/r-tidyr.

Nếu chưa cài đặt, hãy nhập lệnh sau để cài đặt tidyr:

install.packages("tidyr")

tập trung()

Mục tiêu của hàm gather() là chuyển đổi dữ liệu từ định dạng rộng sang định dạng dài.

cú pháp

gather(data, key, value, na.rm = FALSE)
Arguments:
-data: The data frame used to reshape the dataset 
-key: Name of the new column created
-value: Select the columns used to fill the key column
-na.rm: Remove missing values. FALSE by default

Ví dụ

Dưới đây, chúng ta có thể hình dung khái niệm về resha.ping Từ bảng rộng sang bảng dài. Chúng ta muốn tạo một cột duy nhất có tên là "tăng trưởng", được điền bởi các hàng của các biến quý. Hình dưới đây cho thấy bảng rộng ở bên trái và bảng dài đã được định hình lại ở bên phải.

Reshaping Chuyển đổi bảng dữ liệu quý dạng rộng sang định dạng dài bằng chức năng gather của tidyr.

library(tidyr)
# Create a messy dataset
messy <- data.frame(
  country = c("A", "B", "C"),
  q1_2017 = c(0.03, 0.05, 0.01),
  q2_2017 = c(0.05, 0.07, 0.02),
  q3_2017 = c(0.04, 0.05, 0.01),
  q4_2017 = c(0.03, 0.02, 0.04))
messy

Đầu ra:

##   country q1_2017 q2_2017 q3_2017 q4_2017
## 1       A    0.03    0.05    0.04    0.03
## 2       B    0.05    0.07    0.05    0.02
## 3       C    0.01    0.02    0.01    0.04
# Reshape the data
tidier <-messy %>%
gather(quarter, growth, q1_2017:q4_2017)
tidier

Đầu ra:

##    country quarter growth
## 1        A q1_2017   0.03
## 2        B q1_2017   0.05
## 3        C q1_2017   0.01
## 4        A q2_2017   0.05
## 5        B q2_2017   0.07
## 6        C q2_2017   0.02
## 7        A q3_2017   0.04
## 8        B q3_2017   0.05
## 9        C q3_2017   0.01
## 10       A q4_2017   0.03
## 11       B q4_2017   0.02
## 12       C q4_2017   0.04

Trong hàm gather(), chúng ta tạo ra hai biến mới là quarter và growth, bởi vì tập dữ liệu gốc của chúng ta chỉ có một biến nhóm là country và các cặp khóa-giá trị. Trong tidyr 1.0.0 trở lên, thao tác định hình lại tương tự được viết là pivot_longer(messy, cols = q1_2017:q4_2017, names_to = “quarter”, values_to = “growth”).

lây lan()

Hàm spread() thực hiện thao tác ngược lại với hàm gather().

cú pháp

spread(data, key, value)
arguments: 
data: The data frame used to reshape the dataset
key: Column to reshape long to wide
value: Rows used to fill the new column

Ví dụ

Chúng ta có thể chuyển đổi tập dữ liệu gọn gàng trở lại thành dạng lộn xộn bằng hàm spread().

# Reshape the data
messy_1 <- tidier %>%
  spread(quarter, growth) 
messy_1

Đầu ra:

##   country q1_2017 q2_2017 q3_2017 q4_2017
## 1       A    0.03    0.05    0.04    0.03
## 2       B    0.05    0.07    0.05    0.02
## 3       C    0.01    0.02    0.01    0.04

Công thức tương đương hiện đại là pivot_wider(tidier, names_from = quarter, values_from = growth).

chia()

Hàm `separate()` tách một cột thành hai cột dựa trên dấu phân cách. Hàm này hữu ích trong trường hợp biến là ngày tháng. Phân tích của chúng ta có thể cần tập trung vào tháng và năm, và chúng ta muốn tách cột đó thành hai biến mới.

cú pháp

separate(data, col, into, sep= "", remove = TRUE)
arguments:
-data: The data frame used to reshape the dataset 
-col: The column to split
-into: The name of the new variables
-sep: Indicates the symbol used that separates the variable, i.e.:  "-", "_", "&"
-remove: Remove the old column. By default sets to TRUE.

Ví dụ

Chúng ta có thể tách quý khỏi năm trong tập dữ liệu gọn gàng hơn bằng cách áp dụng hàm riêng biệt().

separate_tidier <-tidier %>%
separate(quarter, c("Qrt", "year"), sep ="_")
head(separate_tidier)

Đầu ra:

##   country Qrt year growth
## 1       A  q1 2017   0.03
## 2       B  q1 2017   0.05
## 3       C  q1 2017   0.01
## 4       A  q2 2017   0.05
## 5       B  q2 2017   0.07
## 6       C  q2 2017   0.02

đoàn kết()

Hàm unite() nối hai cột thành một cột.

cú pháp

unite(data, col, conc ,sep= "", remove = TRUE)
arguments:
-data: The data frame used to reshape the dataset 
-col: Name of the new column
-conc: Name of the columns to concatenate
-sep: Indicates the symbol used that unites the variable, i.e:  "-", "_", "&"
-remove: Remove the old columns. By default, sets to TRUE

Ví dụ

Trong ví dụ trên, chúng ta đã tách quý khỏi năm. Vậy nếu muốn gộp chúng lại thì sao? Chúng ta sử dụng đoạn mã sau:

unit_tidier <- separate_tidier %>%
  unite(Quarter, Qrt, year, sep ="_")
head(unit_tidier)

Đầu ra:

##   country Quarter growth
## 1       A q1_2017   0.03
## 2       B q1_2017   0.05
## 3       C q1_2017   0.01
## 4       A q2_2017   0.05
## 5       B q2_2017   0.07
## 6       C q2_2017   0.02

Khung dữ liệu đã được định hình lại hiện đã sẵn sàng cho các bước mô hình hóa được trình bày trong phần còn lại của bài viết. Chuỗi bài hướng dẫn về R.

Câu Hỏi Thường Gặp

Hàm `merge()` thể hiện mọi phép nối thông qua các cờ `all`, `all.x` và `all.y`, trong khi `dplyr` đặt tên cho hành vi trong chính động từ đó. `dplyr` cũng giữ nguyên thứ tự hàng ban đầu và trả về một `tibble`. Phương pháp sử dụng R cơ bản được trình bày trong phần tiếp theo. hợp nhất các khung dữ liệu hướng dẫn.

Chúng là các phép nối lọc, vì vậy chúng không bao giờ thêm cột. semi_join(x, y) giữ lại các hàng của x có khớp với y, và anti_join(x, y) giữ lại các hàng không có khớp. Cả hai đều hữu ích cho việc kiểm tra khóa trước khi thực hiện phép nối biến đổi.

Ánh xạ chúng một cách rõ ràng với `by = c(“ID” = “customer_id”)`, hoặc sử dụng hàm hỗ trợ `join_by(ID == customer_id)` mới hơn. Nếu không có ánh xạping, dplyr khớp với mọi tên cột được chia sẻ, điều này có thể âm thầm thu hẹp kết quả hoặc làm cho kết quả trở nên quá tải.

Một giá trị khóa lặp lại ở cả hai phía, vì vậy mọi sự kết hợp đều được tạo ra. Trước tiên, hãy kiểm tra duplicated() trên từng khóa, tổng hợp phía nhiều, hoặc truyền tham số relationship = “many-to-many” để thể hiện ý định. dplyr sẽ cảnh báo về các kết quả trùng khớp nhiều-nhiều không mong muốn.

filter() chọn các hàng, select() chọn các cột, arrange() phép thuật, mutate() thêm cột, và summarise() thu gọn các nhóm được tạo bởi group_by(). Dấu gạch dọc (|) truyền một kết quả cho động từ tiếp theo; %>% có sẵn trong dplyr và |> là cú pháp gốc của R.

Trợ lý AI có thể lập hồ sơ khung dữ liệu, gắn cờ các khóa trùng lặp hoặc nhập sai trước khi kết hợp, đề xuất cách tái tạo hình ảnh.ping Hãy sử dụng động từ phù hợp với bố cục và giải thích sự thay đổi đột ngột về số hàng bằng ngôn ngữ dễ hiểu. Luôn chạy lại mã và tự kiểm tra kích thước.

Vâng. Trợ lý GitHub Công cụ này hoạt động trên RStudio Desktop 2023.09.0 trở lên và hoàn thành các quy trình join và pivot từ một bình luận. Lưu ý rằng các đề xuất không mang tính xác định, vì vậy hãy xem xét kỹ từng dòng được tạo ra trước khi chạy.

Nối các phép nối, hoặc gấp một danh sách bằng Reduce(function(x, y) left_join(x, y, by = “ID”), list(df1, df2, df3)). purrr::reduce() cũng làm điều tương tự. Kiểm tra nrow() sau mỗi bước, vì các khóa trùng lặp sẽ tích lũy qua các phép nối.

Tóm tắt bài viết này với: