Khóa học
Hướng dẫn data.table trong R này giải thích các khái niệm cơ bản của lệnh DT[i, j, by], phần cốt lõi của gói data.table. Nếu bạn muốn tìm hiểu thêm về gói data.table, DataCamp cung cấp một khóa học R tương tác về gói data.table. Khóa học có hơn 35 bài tập R tương tác - tất cả đều diễn ra ngay trên trình duyệt của bạn - và một số video với Matt Dowle, tác giả chính của gói data.table, và Arun Srinivasan, cộng tác viên lớn. Dùng thử miễn phí.
Nếu bạn từng làm việc với các bộ dữ liệu lớn trong RAM (từ 1 đến hơn 100GB), bạn biết rằng data.frame có thể hạn chế: thời gian thực thi một số thao tác là quá dài. Data.table giải quyết điều này bằng cách rút ngắn thời gian tính toán. Hơn nữa, nó còn giúp bạn làm được nhiều việc hơn với ít thao tác gõ hơn. Khi bạn nắm vững cú pháp data.table từ hướng dẫn này, sự đơn giản khi thực hiện các thao tác phức tạp sẽ khiến bạn ngạc nhiên. Bạn sẽ không chỉ giảm thời gian tính toán mà còn giảm cả thời gian lập trình.
Lệnh DT[i,j,by] có ba phần: i, j và by. Nếu nghĩ theo thuật ngữ SQL, i tương ứng với WHERE, j với SELECT và by với GROUP BY. Ta mô tả lệnh này như sau: “Lấy DT, chọn hàng bằng ‘i’, rồi tính ‘j’ theo nhóm ‘by’”. Với một ví dụ đơn giản dùng bộ dữ liệu hflights (để bạn có thể tái hiện tất cả ví dụ), ta có:
library(hflights)
library(data.table)
DT <- as.data.table(hflights)
DT[Month==10,mean(na.omit(AirTime)), by=UniqueCarrier]
UniqueCarrier V1
AA 68.76471
AS 255.29032
B6 176.93548
CO 141.52861
...
Ở đây, chúng ta đã lọc bảng dữ liệu để chỉ giữ các hàng của tháng 10, tính thời gian bay trung bình của những chuyến thực sự bay (đó là lý do dùng na.omit(), các chuyến bị hủy không có giá trị AirTime) và sau đó nhóm kết quả theo hãng vận chuyển. Ta có thể thấy, chẳng hạn, AA (American Airlines) có thời gian bay trung bình rất ngắn so với AS (Alaska Airlines). Bạn cũng để ý rằng có thể dùng các hàm base R trong phần j? Ta sẽ nói thêm sau.
Phần i
Phần ‘i’ dùng để lọc theo hàng, giống như trong data frame.
DT[2:5]
#selects the second to the fifth row of DT
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime
2011 1 2 7 1401 1501 AA 428 N557AA 60 45
2011 1 3 1 1352 1502 AA 428 N541AA 70 48
2011 1 4 2 1403 1513 AA 428 N403AA 70 39
2011 1 5 3 1405 1507 AA 428 N492AA 62 44
ArrDelay DepDelay Origin Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted
-9 1 IAH DFW 224 6 9 0 0
-8 -8 IAH DFW 224 5 17 0 0
3 3 IAH DFW 224 9 22 0 0
-3 5 IAH DFW 224 9 9 0 0
Nhưng bạn cũng có thể dùng tên cột, vì chúng được đánh giá trong phạm vi của DT.
DT[UniqueCarrier=="AA"]
#Returns all those rows where the Carrier is American Airlines
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime
2011 1 1 6 1400 1500 AA 428 N576AA 60
2011 1 2 7 1401 1501 AA 428 N557AA 60
2011 1 3 1 1352 1502 AA 428 N541AA 70
2011 1 4 2 1403 1513 AA 428 N403AA 70
2011 1 5 3 1405 1507 AA 428 N492AA 62
---
2011 12 27 2 1021 1333 AA 2234 N3ETAA 132
2011 12 28 3 1015 1329 AA 2234 N3FJAA 134
2011 12 29 4 1023 1335 AA 2234 N3GSAA 132
2011 12 30 5 1024 1334 AA 2234 N3BAAA 130
2011 12 31 6 1024 1343 AA 2234 N3HNAA 139
AirTime ArrDelay DepDelay Origin Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted
40 -10 0 IAH DFW 224 7 13 0 0
45 -9 1 IAH DFW 224 6 9 0 0
48 -8 -8 IAH DFW 224 5 17 0 0
39 3 3 IAH DFW 224 9 22 0 0
44 -3 5 IAH DFW 224 9 9 0 0
---
112 -12 1 IAH MIA 964 8 12 0 0
112 -16 -5 IAH MIA 964 9 13 0 0
110 -10 3 IAH MIA 964 12 10 0 0
110 -11 4 IAH MIA 964 9 11 0 0
119 -2 4 IAH MIA 964 8 12 0 0
Lưu ý bạn không cần dùng dấu phẩy khi lọc hàng trong data table. Trong data.frame, làm DF[2:5] sẽ trả về tất cả các hàng của cột 2 đến 5. Thay vào đó (như ai đang đọc bài này hẳn đều biết), ta phải ghi DF[2:5,]. Cũng lưu ý rằng DT[,2:5] không có ý nghĩa với data table, như đã giải thích ở câu hỏi đầu tiên trong phần Câu hỏi thường gặp (FAQ) của gói data.table.
Vừa lạ vừa hữu ích: khi lọc hàng, bạn có thể dùng ký hiệu .N trong lệnh DT[…], là số hàng hoặc hàng cuối cùng. Bạn có thể dùng nó để chọn hàng cuối hoặc lùi từ cuối lên.
DT[.N-1]
#Returns the penultimate row of DT
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime
2011 12 6 2 656 812 WN 621 N727SW 76 64
ArrDelay DepDelay Origin Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted
-13 -4 HOU TUL 453 3 9 0 0
Phần j
Phần ‘j’ dùng để chọn cột và làm các thao tác trên chúng. Và các thao tác ở đây thực sự có thể là bất kỳ điều gì. Mọi loại hàm đều có thể sử dụng, đây là điểm mạnh của gói data.table.
DT[, mean(na.omit(ArrDelay))]
[1] 7.094334
Lưu ý phần 'i' để trống, và thứ đầu tiên trong dấu ngoặc là dấu phẩy. Ban đầu có thể thấy khó hiểu. Tuy nhiên, điều này đơn giản nghĩa là ta không lọc theo hàng nào cả, nên tất cả hàng đều được chọn. Ở phần 'j', ta tính độ trễ khi đến trung bình của tất cả các chuyến bay. Có vẻ chiếc máy bay trung bình trong bộ dữ liệu hflights bị trễ hơn 7 phút. Hãy chuẩn bị tinh thần cho chuyến bay tiếp theo của bạn!
Khi chọn nhiều cột và làm các thao tác với chúng trong phần 'j', bạn cần dùng ký pháp ‘.()’. Ký pháp này thực chất chỉ là bí danh của ‘list()’. Nó trả về một data table, còn nếu không dùng ‘.()’ thì chỉ trả về một vector, như đã thấy ở trên.
DT[, .(mean(na.omit(DepDelay)), mean(na.omit(ArrDelay)))]
V1 V2
9.444951 7.094334
Một tính năng hữu ích khác, yêu cầu ký pháp ‘.()’, cho phép bạn đổi tên cột ngay trong lệnh DT[…].
DT[, .(Avg_ArrDelay =
mean(na.omit(ArrDelay)))]
Avg_ArrDelay
7.094334
DT[, .(Avg_DepDelay = mean(na.omit(DepDelay)),
avg_ArrDelay = mean(na.omit(ArrDelay)))]
Avg_DepDelay Avg_ArrDelay
9.444951 7.094334
Tất nhiên, không bắt buộc phải đặt tên cột mới.
Kết hợp những điều trên về ‘i’ và ‘j’ cho ta:
DT[UniqueCarrier=="AA", .(Avg_DepDelay =
mean(na.omit(DepDelay)),
Avg_ArrDelay = mean(na.omit(ArrDelay)),
plot(DepTime,DepDelay,ylim=c(-15,200)),
abline(h=0))]
Avg_DepDelay Avg_ArrDelay V3 V4
6.390144 0.8917558 NULL NULL
Ở đây ta lấy DT, chọn tất cả hàng có hãng là AA trong phần 'i', tính độ trễ trung bình khi khởi hành và khi đến, và vẽ đồ thị thời điểm khởi hành so với độ trễ khi khởi hành trong phần 'j'.
Tóm lại, phần ‘j’ dùng để thực hiện các phép tính trên những cột được chỉ định trong phần này. Vì các cột của data table được xem như biến, và các phần trong ‘j’ được đánh giá như các biểu thức, gần như có thể làm bất cứ điều gì trong phần ‘j’. Điều này rút ngắn đáng kể thời gian lập trình của bạn.
Phần by
Phần cuối của hướng dẫn data.table trong R này tập trung vào phần ‘by’. Phần ‘by’ được dùng khi ta muốn tính phần ‘j’ theo nhóm bởi một biến cụ thể (hoặc một phép biến đổi của biến đó). Bạn sẽ thấy biểu thức ‘j’ được lặp lại cho mỗi nhóm 'by'. Cách dùng rất đơn giản: bạn chỉ cần chỉ định cột muốn nhóm theo trong đối số 'by'.
DT[,mean(na.omit(DepDelay)),by=Origin]
Origin V1
IAH 8.436951
HOU 12.837873
Ở đây, chúng ta tính độ trễ trung bình trước khi khởi hành, nhưng nhóm theo nơi máy bay xuất phát. Có vẻ các chuyến rời HOU bị trễ trung bình nhiều hơn so với rời IAH.
Cũng như phần 'j', bạn có thể làm rất nhiều thao tác trong phần 'by'. Có thể dùng các hàm trong phần 'by' để kết quả của các phép trong phần 'j' được nhóm theo thứ gì đó ta chỉ định ngay trong lệnh DT[…]. Việc dùng hàm bên trong DT[…] khiến một dòng lệnh trở nên rất mạnh. Tương tự, cần dùng ký pháp ‘.()’ khi dùng nhiều cột trong phần 'by'.
DT[,.(Avg_DepDelay_byWeekdays = mean(na.omit(DepDelay))), by=.(Origin,Weekdays = DayOfWeek<6)]
Origin Weekdays Avg_DepDelay_byWeekdays
IAH FALSE 8.286543
IAH TRUE 8.492484
HOU FALSE 10.965384
HOU TRUE 13.433994
Ở đây, độ trễ trung bình trước khi khởi hành của tất cả máy bay (không lọc ở phần 'i', nên chọn tất cả hàng) được tính trước, rồi nhóm sau, thứ nhất theo nơi xuất phát và thứ hai theo ngày trong tuần. Weekdays là False vào cuối tuần. Có vẻ độ trễ trung bình trước khi khởi hành lớn hơn khi máy bay rời HOU so với IAH, và bất ngờ là độ trễ lại nhỏ hơn vào cuối tuần.
Kết hợp tất cả, một lệnh DT[i,j,by] điển hình cho ta:
DT[UniqueCarrier=="DL", .(Avg_DepDelay =
mean(na.omit(DepDelay)),
Avg_ArrDelay = mean(na.omit(ArrDelay)),
Compensation = mean(na.omit(ArrDelay - DepDelay))), by = .(Origin, Weekdays = DayOfWeek&lt;6)]
Origin Weekdays Avg_DepDelay Avg_ArrDelay Compensation
IAH FALSE 8.979730 4.116751 -4.825719
HOU FALSE 7.120000 2.656566 -4.555556
IAH TRUE 9.270948 6.281941 -2.836609
HOU TRUE 11.631387 10.406593 -1.278388
Ở đây, tập con các chuyến bay do Delta Air Lines khai thác (được chọn trong 'i') được nhóm theo nơi xuất phát và theo Weekdays (trong 'by'). Thời gian được bù trong khi bay cũng được tính (trong 'j'). Có vẻ vào cuối tuần, bất kể máy bay rời IAH hay HOU, thời gian được bù khi ở trên không (tức bay nhanh hơn) đều lớn hơn.
Còn rất nhiều điều để khám phá trong gói data.table, nhưng bài viết này đã minh họa lệnh cơ bản DT[i,j,by]. Khóa học của DataCamp giải thích toàn diện gói data.table. Bạn có thể làm bài tập theo nhịp độ của riêng mình ngay trên trình duyệt với gợi ý và phản hồi, và xem lại video cùng slide bất cứ lúc nào. Cách học tương tác này giúp bạn nắm vững kiến thức và kinh nghiệm thực hành với data.table. Dùng thử miễn phí. Xem thêm Cheat Sheet gói data.table cho R của DataCamp.
Hy vọng nhờ hướng dẫn data.table trong R này, bạn đã hiểu cú pháp nền tảng của data.table và sẵn sàng tự mình thử nghiệm. Nếu có câu hỏi về gói data.table, hãy xem tại đây. Matt và Arun rất tích cực trả lời. Một trong các bài viết sắp tới về gói data.table sẽ mang tính kỹ thuật hơn, đi sâu vào những khả năng phong phú của data.table. Hãy đón đọc!

