Menu

Kiểu dữ liệu trong R: numeric, character, logical (typeof, class)

Các kiểu dữ liệu nguyên tử trong R (double, integer, character, logical), khác biệt giữa typeof() và class(), cùng cách chuyển đổi và ép kiểu hoạt động.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Các kiểu dữ liệu trong R

Mọi giá trị trong R đều thuộc một trong vài kiểu nguyên tử (atomic type). Bốn kiểu trong số đó gánh gần như toàn bộ công việc:

  • double: số thập phân như 3.14, -2, 1e6. Đây là thứ R gọi là "numeric", và là kiểu mặc định cho mọi con số bạn gõ.
  • integer: số nguyên được lưu chính xác, viết với hậu tố L: 42L.
  • character: văn bản trong dấu nháy: "hello".
  • logical: hai giá trị chân lý TRUE và FALSE (cùng với NA, giá trị thiếu; xem giá trị thiếu).

Ngoài ra còn có complex (2 + 3i) cho đôi chút toán xử lý tín hiệu; bạn có thể làm việc nhiều năm mà không cần đến nó. typeof() cho biết một giá trị thuộc kiểu nào:

Hãy để ý dòng đầu tiên: một con số thông thường là double ngay cả khi trông như số nguyên. typeof(42) là "double"; chỉ 42L mới là integer. Trong phân tích hằng ngày, sự khác biệt này hiếm khi quan trọng vì R chuyển đổi giữa chúng một cách lặng lẽ, nhưng nó giải thích rất nhiều kết quả khó hiểu từ typeof().

typeof() và class(): vì sao chúng không khớp nhau

R có hai hàm trông như cùng trả lời câu hỏi "đây là gì?", nhưng thực ra chúng trả lời hai câu hỏi hơi khác nhau.

  • typeof() cho biết kiểu lưu trữ: giá trị nằm trong bộ nhớ ra sao.
  • class() cho biết kiểu hành vi: nhãn mà cơ chế gọi phương thức của R dùng để quyết định, chẳng hạn, nên chạy print hay summary nào.

Với các giá trị đơn giản, câu trả lời chỉ khác nhau ở cách gọi tên:

typeof() nói double (cách lưu trữ), class() nói numeric (cách hành xử). Với các cấu trúc, khoảng cách còn lớn hơn:

Ma trận được lưu như một vector integer bình thường, nhưng nó hành xử như một ma trận: chính class() báo cho R in nó ra dạng lưới. Sự tách biệt tương tự xuất hiện với data frame (typeof nói "list", class nói "data.frame") và ngày tháng (typeof nói "double", class nói "Date").

Quy tắc thực tế: dùng class() khi bạn muốn biết một thứ là gì theo nghĩa thông thường, và typeof() khi bạn gỡ lỗi xem R đang làm gì bên dưới.

Kiểm tra kiểu với is.*()

Mỗi kiểu có một hàm kiểm tra tương ứng trả về TRUE hoặc FALSE, rất tiện bên trong các hàm cần xác thực đầu vào:

Một cái bẫy nên biết: is.numeric() là TRUE cho cả double lẫn integer (vì cả hai đều là số), nhưng is.integer() kiểm tra cách lưu trữ, nên nó là FALSE với một số 42 thông thường:

Nếu bạn từng ngạc nhiên vì is.integer(7) là FALSE dù đó rõ ràng là số nguyên theo nghĩa toán học, thì đây là lý do. 7 là double; 7L mới là integer.

Chuyển đổi kiểu với as.*()

Chuyển đổi tường minh dùng nhóm hàm as.*, mỗi kiểu đích một hàm:

Có hai hành vi cần nhớ. as.integer() cắt bỏ phần thập phân về phía 0 chứ không làm tròn: 7.9 thành 7. Và khi một phép chuyển đổi vô nghĩa, R không báo lỗi; nó trả về NA và đưa ra cảnh báo:

Chạy đoạn đó và bạn sẽ thấy NA kèm cảnh báo "NAs introduced by coercion". Điều này thực sự hữu ích: chuyển cả một cột văn bản lộn xộn thành số, các giá trị không đọc được sẽ thành NA thay vì làm script bị dừng. Nhưng nó cũng có nghĩa là một NA có thể lặng lẽ lọt vào dữ liệu của bạn. Khi một phép chuyển đổi quan trọng, hãy kiểm tra xem có NA mới nào xuất hiện sau đó không.

Giá trị logic chuyển qua lại với số đúng như bạn mong đợi: as.numeric(TRUE) là 1, as.logical(0) là FALSE. Đó là lý do sum() trên một vector logic sẽ đếm số TRUE:

Ép kiểu ngầm: quy tắc một kiểu cho vector

Một vector nguyên tử trong R chỉ chứa được một kiểu. Khi gộp các giá trị khác kiểu bằng c(), R lặng lẽ nâng mọi thứ lên kiểu linh hoạt nhất có mặt, theo một bậc thang cố định:

logical → integer → double → character

Các giá trị logic thành 1 và 0, integer thành double, và ở dòng cuối mọi thứ thành văn bản: character luôn thắng, vì giá trị nào cũng viết được thành chuỗi. Bạn có thể xác nhận bằng typeof():

Ép kiểu là nguồn số một của các bug kiểu "sao cột của mình lại là văn bản?": chỉ một chuỗi "N/A" lạc loài trong một cột số cũng ép cả vector thành character. Khi điều đó xảy ra, hãy sửa giá trị gây lỗi trước, rồi chuyển lại bằng as.numeric().

Những điều cần nhớ

  • Bốn kiểu chủ lực: double ("numeric"), integer (42L), character, logical.
  • typeof() = cách lưu trữ; class() = cách hành xử. 3.14 là một double hành xử như numeric.
  • Kiểm tra bằng is.numeric() và các hàm cùng nhóm; chuyển đổi bằng as.numeric() và các hàm cùng nhóm. Chuyển đổi thất bại cho NA kèm cảnh báo, không phải lỗi.
  • Vector chỉ chứa một kiểu; trộn kiểu sẽ ép theo thứ tự logical → integer → double → character.

Tiếp theo: xem kỹ hơn các kiểu số, gồm làm tròn, hàm toán học và những bất ngờ của số thực dấu phẩy động mà ngôn ngữ nào cũng có.

Câu hỏi thường gặp

Các kiểu dữ liệu cơ bản trong R là gì?

Các kiểu nguyên tử gồm double (số thập phân, R gọi là "numeric"), integer (số nguyên, viết với hậu tố L như 42L), character (văn bản trong dấu nháy), logical (TRUE/FALSE) và complex hiếm khi dùng. Mọi thứ lớn hơn như vector, data frame, list đều được xây từ những kiểu này.

typeof() và class() trong R khác nhau thế nào?

typeof() cho biết giá trị được lưu trong bộ nhớ ra sao (kiểu cấp thấp); class() cho biết giá trị hành xử như thứ gì, điều quyết định R gọi phương thức nào. Với một số thập phân thông thường, chúng chỉ khác nhau về tên gọi: typeof(3.14) là "double" còn class(3.14) là "numeric". Với các cấu trúc như data frame, typeof() nói "list" còn class() nói "data.frame".

Làm sao để chuyển đổi kiểu trong R?

Dùng nhóm hàm as.*: as.numeric("3.5") cho 3.5, as.character(42) cho "42", as.integer(7.9) cắt bỏ phần thập phân thành 7. Khi không thể chuyển đổi, R trả về NA và đưa ra cảnh báo chứ không báo lỗi: as.numeric("abc") là NA.

Ép kiểu (coercion) trong R là gì?

Khi bạn gộp nhiều kiểu khác nhau vào một vector, R lặng lẽ chuyển mọi thứ sang kiểu linh hoạt nhất, theo thứ tự logical → integer → double → character. Vì vậy c(1, 2, "three") trở thành một vector character: "1" "2" "three".

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu