Code
::p_load(
pacman# xử lý data
data.table, # vẽ bảng
kableExtra )
Data processing series - R
Đối với xử lý dữ liệu, việc gộp dữ liệu đóng vai trò rất quan trọng khi chúng ta có từ hai bảng dữ liệu trở lên hoặc làm việc với cơ sở dữ liệu. Equi-join là loại gộp dữ liệu từ các bảng dữ liệu có (các) biến liên quan có dữ liệu giống nhau (còn được biết đến là các keys), vốn đã rất phổ biến và là tiêu chuẩn cần có của một người làm data hiện nay. Tuy nhiên, điều này ngược lại đối với non-equi joins, một loại gộp dữ liệu linh hoạt hơn nhưng lại ít được biết đến. Thông thường, một loại gộp dữ liệu sẽ bao gồm nhiều cách gộp dữ liệu khác nhau tùy vào mục đích gộp cụ thể. Bài viết này sẽ sử dụng cách gộp rolling joins trong non-equi joins và ứng dụng cách gộp này vào trong kinh doanh thông qua gói lệnh data.table
trong ngôn ngữ R.
Một doanh nghiệp A sở hữu một trang web thương mại điện tử có sử dụng bên thứ ba để thực hiện thanh toán chẳng hạn như MoMo. Doanh nghiệp theo dõi các phiên đăng nhập của người dùng thông qua trang web và MoMo theo dõi việc thanh toán của khách hàng khi thực hiện mua hàng. Mục đích của doanh nghiệp muốn biết rằng phiên đăng nhập nào thì sẽ dẫn tới việc quyết định mua hàng.
Trước tiên tôi gọi các gói lệnh mà tôi cần sử dụng trong bài viết này.
::p_load(
pacman# xử lý data
data.table, # vẽ bảng
kableExtra )
Bây giờ tôi sẽ tạo ra một 2 bảng dữ liệu mẫu. Trong đó, một bảng chứa dữ liệu về thông tin đa dạng kiểu khách hàng và thời điểm truy cập, bảng còn lại chứa thông tin và thời điểm thanh toán.
Một Suzy với nhiều lần truy cập trang web trước khi mua bất cứ thứ gì
<- data.table(name = rep('Indecisive Suzy', 5),
suzy_website session_start_time = as.POSIXct(
c(
'2024-01-01 11:01',
'2024-01-02 8:59',
'2024-01-05 18:18',
'2024-01-07 19:03',
'2024-01-08 19:01'
)
))<-
suzy_momo data.table(name = 'Indecisive Suzy',
purchase_time = as.POSIXct('2024-01-08 19:10'))
Một Adam “phóng khoáng” khi chỉ truy cập trang web một lần và mua nhiều lần
<-
adam_website data.table(name = 'Spendy Adam',
session_start_time = as.POSIXct('2024-01-03 10:00'))
<-
adam_momo data.table(name = rep('Spendy Adam', 2),
purchase_time = as.POSIXct(c('2024-01-03 10:06', '2024-01-03 10:15')))
Một Tom thường đến trang web mua sắm và thỉnh thoảng mua hàng
<- data.table(name = rep('Frequent Tom', 6),
tom_website session_start_time = as.POSIXct(
c(
'2024-01-02 13:09',
'2024-01-03 19:22',
'2024-01-08 8:44',
'2024-01-08 20:22',
'2024-01-10 17:36',
'2024-01-15 16:56'
)
))<-
tom_momo data.table(name = rep('Frequent Tom', 3),
purchase_time = as.POSIXct(c(
'2024-01-03 19:28', '2024-01-08 20:33', '2024-01-10 17:46'
)))
Một Jane “vãng lai” ghé qua trang web vài lần nhưng không mua gì cả
<-
jane_website data.table(name = rep('Visitor Jane', 2),
session_start_time = as.POSIXct(c('2024-01-01 9:10', '2024-01-09 2:15')))
<- character(0) # has 0 rows, but the same column names/classes jane_momo
Một Jessica thanh toán qua MoMo mà không truy cập trang web (ghé qua cửa hàng và thanh toán trực tuyến)
<- character(0)
jessica_website <- data.table(name = 'Non-web Jessica', purchase_time = as.POSIXct('2023-12-02 17:58')) jessica_momo
Kết hợp tất cả lại ta có được 2 bảng dữ liệu như sau
<-
table_style function(table, caption) {
kbl(table, caption = caption,
table.attr = 'data-quarto-disable-processing="true"') |>
kable_classic(
bootstrap_options = c("condensed"),
full_width = F,
html_font = "Arial",
font_size = 15
|>
) row_spec(0, bold = T)
}
<-
website rbindlist(list(
adam_website,
jane_website,# jessica_website,
suzy_website,
tom_website
))
<- rbindlist(list(adam_momo, jessica_momo, suzy_momo, tom_momo))
momo
|> table_style("Bảng theo dõi phiên đăng nhập") website
name | session_start_time |
---|---|
Spendy Adam | 2024-01-03 10:00:00 |
Visitor Jane | 2024-01-01 09:10:00 |
Visitor Jane | 2024-01-09 02:15:00 |
Indecisive Suzy | 2024-01-01 11:01:00 |
Indecisive Suzy | 2024-01-02 08:59:00 |
Indecisive Suzy | 2024-01-05 18:18:00 |
Indecisive Suzy | 2024-01-07 19:03:00 |
Indecisive Suzy | 2024-01-08 19:01:00 |
Frequent Tom | 2024-01-02 13:09:00 |
Frequent Tom | 2024-01-03 19:22:00 |
Frequent Tom | 2024-01-08 08:44:00 |
Frequent Tom | 2024-01-08 20:22:00 |
Frequent Tom | 2024-01-10 17:36:00 |
Frequent Tom | 2024-01-15 16:56:00 |
|> table_style("Bảng theo dõi việc thanh toán") momo
name | purchase_time |
---|---|
Spendy Adam | 2024-01-03 10:06:00 |
Spendy Adam | 2024-01-03 10:15:00 |
Non-web Jessica | 2023-12-02 17:58:00 |
Indecisive Suzy | 2024-01-08 19:10:00 |
Frequent Tom | 2024-01-03 19:28:00 |
Frequent Tom | 2024-01-08 20:33:00 |
Frequent Tom | 2024-01-10 17:46:00 |
Trong trường hợp thực tế, tôi cần tạo các mã ID riêng biệt cho từng phiên đăng nhập và từng thời điểm thanh toán. Sau cùng, ta sẽ có 2 bảng dữ liệu như sau
:= .GRP, by = .(name, session_start_time)]
website[, session_id
:= .GRP, by = .(name, purchase_time)]
momo[, payment_id
|> table_style("Bảng theo dõi phiên đăng nhập") website
name | session_start_time | session_id |
---|---|---|
Spendy Adam | 2024-01-03 10:00:00 | 1 |
Visitor Jane | 2024-01-01 09:10:00 | 2 |
Visitor Jane | 2024-01-09 02:15:00 | 3 |
Indecisive Suzy | 2024-01-01 11:01:00 | 4 |
Indecisive Suzy | 2024-01-02 08:59:00 | 5 |
Indecisive Suzy | 2024-01-05 18:18:00 | 6 |
Indecisive Suzy | 2024-01-07 19:03:00 | 7 |
Indecisive Suzy | 2024-01-08 19:01:00 | 8 |
Frequent Tom | 2024-01-02 13:09:00 | 9 |
Frequent Tom | 2024-01-03 19:22:00 | 10 |
Frequent Tom | 2024-01-08 08:44:00 | 11 |
Frequent Tom | 2024-01-08 20:22:00 | 12 |
Frequent Tom | 2024-01-10 17:36:00 | 13 |
Frequent Tom | 2024-01-15 16:56:00 | 14 |
|> table_style("Bảng theo dõi việc thanh toán") momo
name | purchase_time | payment_id |
---|---|---|
Spendy Adam | 2024-01-03 10:06:00 | 1 |
Spendy Adam | 2024-01-03 10:15:00 | 2 |
Non-web Jessica | 2023-12-02 17:58:00 | 3 |
Indecisive Suzy | 2024-01-08 19:10:00 | 4 |
Frequent Tom | 2024-01-03 19:28:00 | 5 |
Frequent Tom | 2024-01-08 20:33:00 | 6 |
Frequent Tom | 2024-01-10 17:46:00 | 7 |
Trước khi tiến hành gộp dữ liệu, tôi muốn tạo một biến thời điểm tương tự như cũ cho mỗi bảng dữ liệu để gộp bởi vì khi gộp một trong hai bảng sẽ mất đi một biến thời điểm và không dễ để xác định của đó là của bảng nào
:= session_start_time]
website[, join_time := purchase_time]
momo[, join_time
|> table_style("Bảng theo dõi phiên đăng nhập") website
name | session_start_time | session_id | join_time |
---|---|---|---|
Spendy Adam | 2024-01-03 10:00:00 | 1 | 2024-01-03 10:00:00 |
Visitor Jane | 2024-01-01 09:10:00 | 2 | 2024-01-01 09:10:00 |
Visitor Jane | 2024-01-09 02:15:00 | 3 | 2024-01-09 02:15:00 |
Indecisive Suzy | 2024-01-01 11:01:00 | 4 | 2024-01-01 11:01:00 |
Indecisive Suzy | 2024-01-02 08:59:00 | 5 | 2024-01-02 08:59:00 |
Indecisive Suzy | 2024-01-05 18:18:00 | 6 | 2024-01-05 18:18:00 |
Indecisive Suzy | 2024-01-07 19:03:00 | 7 | 2024-01-07 19:03:00 |
Indecisive Suzy | 2024-01-08 19:01:00 | 8 | 2024-01-08 19:01:00 |
Frequent Tom | 2024-01-02 13:09:00 | 9 | 2024-01-02 13:09:00 |
Frequent Tom | 2024-01-03 19:22:00 | 10 | 2024-01-03 19:22:00 |
Frequent Tom | 2024-01-08 08:44:00 | 11 | 2024-01-08 08:44:00 |
Frequent Tom | 2024-01-08 20:22:00 | 12 | 2024-01-08 20:22:00 |
Frequent Tom | 2024-01-10 17:36:00 | 13 | 2024-01-10 17:36:00 |
Frequent Tom | 2024-01-15 16:56:00 | 14 | 2024-01-15 16:56:00 |
|> table_style("Bảng theo dõi việc thanh toán") momo
name | purchase_time | payment_id | join_time |
---|---|---|---|
Spendy Adam | 2024-01-03 10:06:00 | 1 | 2024-01-03 10:06:00 |
Spendy Adam | 2024-01-03 10:15:00 | 2 | 2024-01-03 10:15:00 |
Non-web Jessica | 2023-12-02 17:58:00 | 3 | 2023-12-02 17:58:00 |
Indecisive Suzy | 2024-01-08 19:10:00 | 4 | 2024-01-08 19:10:00 |
Frequent Tom | 2024-01-03 19:28:00 | 5 | 2024-01-03 19:28:00 |
Frequent Tom | 2024-01-08 20:33:00 | 6 | 2024-01-08 20:33:00 |
Frequent Tom | 2024-01-10 17:46:00 | 7 | 2024-01-10 17:46:00 |
Bây giờ ta sẽ trả lời câu hỏi “phiên đăng nhập nào được thực hiện trước thời điểm thanh toán?”
= .(name, join_time), roll = T] |> # tương đương với website[momo, on = .(join_time), roll = Inf]
website[momo, on table_style("")
name | session_start_time | session_id | join_time | purchase_time | payment_id |
---|---|---|---|---|---|
Spendy Adam | 2024-01-03 10:00:00 | 1 | 2024-01-03 10:06:00 | 2024-01-03 10:06:00 | 1 |
Spendy Adam | 2024-01-03 10:00:00 | 1 | 2024-01-03 10:15:00 | 2024-01-03 10:15:00 | 2 |
Non-web Jessica | NA | NA | 2023-12-02 17:58:00 | 2023-12-02 17:58:00 | 3 |
Indecisive Suzy | 2024-01-08 19:01:00 | 8 | 2024-01-08 19:10:00 | 2024-01-08 19:10:00 | 4 |
Frequent Tom | 2024-01-03 19:22:00 | 10 | 2024-01-03 19:28:00 | 2024-01-03 19:28:00 | 5 |
Frequent Tom | 2024-01-08 20:22:00 | 12 | 2024-01-08 20:33:00 | 2024-01-08 20:33:00 | 6 |
Frequent Tom | 2024-01-10 17:36:00 | 13 | 2024-01-10 17:46:00 | 2024-01-10 17:46:00 | 7 |
Trong bảng kết quả:
Giờ ta sẽ đổi vị trí của hai bảng và trả lời câu hỏi “phiên đăng nhập nào quyết định việc thanh toán?”
= .(name, join_time), roll = -Inf] |>
momo[website, on table_style("")
name | purchase_time | payment_id | join_time | session_start_time | session_id |
---|---|---|---|---|---|
Spendy Adam | 2024-01-03 10:06:00 | 1 | 2024-01-03 10:00:00 | 2024-01-03 10:00:00 | 1 |
Visitor Jane | NA | NA | 2024-01-01 09:10:00 | 2024-01-01 09:10:00 | 2 |
Visitor Jane | NA | NA | 2024-01-09 02:15:00 | 2024-01-09 02:15:00 | 3 |
Indecisive Suzy | 2024-01-08 19:10:00 | 4 | 2024-01-01 11:01:00 | 2024-01-01 11:01:00 | 4 |
Indecisive Suzy | 2024-01-08 19:10:00 | 4 | 2024-01-02 08:59:00 | 2024-01-02 08:59:00 | 5 |
Indecisive Suzy | 2024-01-08 19:10:00 | 4 | 2024-01-05 18:18:00 | 2024-01-05 18:18:00 | 6 |
Indecisive Suzy | 2024-01-08 19:10:00 | 4 | 2024-01-07 19:03:00 | 2024-01-07 19:03:00 | 7 |
Indecisive Suzy | 2024-01-08 19:10:00 | 4 | 2024-01-08 19:01:00 | 2024-01-08 19:01:00 | 8 |
Frequent Tom | 2024-01-03 19:28:00 | 5 | 2024-01-02 13:09:00 | 2024-01-02 13:09:00 | 9 |
Frequent Tom | 2024-01-03 19:28:00 | 5 | 2024-01-03 19:22:00 | 2024-01-03 19:22:00 | 10 |
Frequent Tom | 2024-01-08 20:33:00 | 6 | 2024-01-08 08:44:00 | 2024-01-08 08:44:00 | 11 |
Frequent Tom | 2024-01-08 20:33:00 | 6 | 2024-01-08 20:22:00 | 2024-01-08 20:22:00 | 12 |
Frequent Tom | 2024-01-10 17:46:00 | 7 | 2024-01-10 17:36:00 | 2024-01-10 17:36:00 | 13 |
Frequent Tom | NA | NA | 2024-01-15 16:56:00 | 2024-01-15 16:56:00 | 14 |
Trong bảng kết quả:
Nếu muốn thêm một điều kiện cho cách gộp ở trên: gộp thanh toán cho phiên đăng nhập với sao cho thời điểm thanh toán xuất hiện sau khi đăng nhập và cả 2 chỉ trong vòng 12 tiếng
<- 60 * 60 * 12 # 12 tiếng = 60 giây * 60 phút * 12 giờ
condition
= .(name, join_time),roll = -condition] |>
momo[website, on table_style("")
name | purchase_time | payment_id | join_time | session_start_time | session_id |
---|---|---|---|---|---|
Spendy Adam | 2024-01-03 10:06:00 | 1 | 2024-01-03 10:00:00 | 2024-01-03 10:00:00 | 1 |
Visitor Jane | NA | NA | 2024-01-01 09:10:00 | 2024-01-01 09:10:00 | 2 |
Visitor Jane | NA | NA | 2024-01-09 02:15:00 | 2024-01-09 02:15:00 | 3 |
Indecisive Suzy | NA | NA | 2024-01-01 11:01:00 | 2024-01-01 11:01:00 | 4 |
Indecisive Suzy | NA | NA | 2024-01-02 08:59:00 | 2024-01-02 08:59:00 | 5 |
Indecisive Suzy | NA | NA | 2024-01-05 18:18:00 | 2024-01-05 18:18:00 | 6 |
Indecisive Suzy | NA | NA | 2024-01-07 19:03:00 | 2024-01-07 19:03:00 | 7 |
Indecisive Suzy | 2024-01-08 19:10:00 | 4 | 2024-01-08 19:01:00 | 2024-01-08 19:01:00 | 8 |
Frequent Tom | NA | NA | 2024-01-02 13:09:00 | 2024-01-02 13:09:00 | 9 |
Frequent Tom | 2024-01-03 19:28:00 | 5 | 2024-01-03 19:22:00 | 2024-01-03 19:22:00 | 10 |
Frequent Tom | 2024-01-08 20:33:00 | 6 | 2024-01-08 08:44:00 | 2024-01-08 08:44:00 | 11 |
Frequent Tom | 2024-01-08 20:33:00 | 6 | 2024-01-08 20:22:00 | 2024-01-08 20:22:00 | 12 |
Frequent Tom | 2024-01-10 17:46:00 | 7 | 2024-01-10 17:36:00 | 2024-01-10 17:36:00 | 13 |
Frequent Tom | NA | NA | 2024-01-15 16:56:00 | 2024-01-15 16:56:00 | 14 |