Skip to content

↑ R1 · ← Data Structures · → Control Flow & Functions

🎯 Mục tiêu

Bạn không ship được pipeline “đáng tin” nếu không kiểm soát được: (1) kiểu dữ liệu, (2) missingness, (3) coercion, và (4) attributes. Đây là chỗ sai phổ biến nhất trong production vì bug thường không crash mà chỉ… ra số liệu sai.

1) Types trong R: core set bạn phải nắm

1.1 Atomic types (vector-based)

Atomic vector có 1 kiểu duy nhất. Core types:

  • logical (TRUE/FALSE)
  • integer (thường viết 1L)
  • double (numeric mặc định, ví dụ 1 là double)
  • character
  • complex
  • raw
r
typeof(TRUE)   # "logical"
typeof(1L)     # "integer"
typeof(1)      # "double"
typeof("a")    # "character"

Khi làm ops, câu hỏi đúng không phải “trông giống số” mà là:

  • typeof(x) là gì?
  • is.integer(x) hay is.numeric(x)?

1.2 “Type” vs “class”

typeof() là kiểu storage level. class() là attribute giúp dispatch method (S3).

r
x <- 1:3
typeof(x)   # "integer"
class(x)    # "integer"

y <- as.Date("2026-01-30")
typeof(y)   # "double"
class(y)    # "Date"

Kết luận quan trọng: Nhiều object trong R “trông như kiểu mới” nhưng thực ra là atomic vector + class.

⚠️ Cạm bẫy

Khi bạn unclass() hoặc làm thao tác vô tình rớt class, các hàm in/format/plot có thể đổi hành vi hoàn toàn mà không báo lỗi.

2) Missingness: NA vs NaN vs NULL (và hệ quả trong ops)

2.1 Định nghĩa nhanh

  • NA: “missing value” theo kiểu (có thể là NA_integer_, NA_real_, NA_character_, ...)
  • NaN: “Not a Number” (kết quả toán học không xác định), là một dạng đặc biệt của numeric
  • NULL: “không có gì” / “absent object” (length 0), hay gặp khi field không tồn tại

2.2 Hành vi thực tế bạn phải dự đoán

r
is.na(NA)            # TRUE
is.nan(NA)           # FALSE
is.na(NaN)           # TRUE
is.nan(NaN)          # TRUE

length(NULL)         # 0
is.null(NULL)        # TRUE
is.na(NULL)          # logical(0)

2.3 Ops pitfalls (điểm hay sai trong production)

Pitfall A — NA trong điều kiện if

r
flag <- NA
if (flag) "yes"      # Error: missing value where TRUE/FALSE needed

Giải pháp: luôn biến điều kiện thành boolean chắc chắn:

r
if (isTRUE(flag)) "yes"

Pitfall B — Summary sai vì default na.rm = FALSE

r
mean(c(1, 2, NA))    # NA
mean(c(1, 2, NA), na.rm = TRUE)  # 1.5

Ops implication: bạn phải có “missingness policy” rõ ràng:

  • Cột nào cho phép missing?
  • Missing xử lý ở đâu: ingest, transform, hay report?

Pitfall C — Joins + missing keys Nếu key có NA, join có thể tạo số dòng unexpected (tùy thư viện/logic). Quy tắc kỹ sư:

  • validate keys trước join: không missing, không duplicate (trừ khi cố ý).

✅ Checklist triển khai

Missingness policy tối thiểu (ship-ready)

  • Define schema: cột bắt buộc + kiểu mong muốn + missing allowed?
  • Trước join: check key !anyNA(key) và uniqueness nếu cần
  • Trước summary: quyết định na.rm và log tỷ lệ missing
  • Trước export: chuẩn hóa missing representation (NA vs empty string) theo consumer

3) Coercion: thứ khiến bug “im lặng”

R sẽ tự chuyển kiểu để “make it work”. Trong production, đó là con dao hai lưỡi.

3.1 Coercion ladder (thực dụng)

Khi trộn kiểu trong c(...) hoặc nhiều phép toán, thường bị “nâng” theo hướng: logicalintegerdoublecharacter

r
c(TRUE, 1L)      # integer
c(1L, 1.5)       # double
c(1.5, "2")      # character

3.2 “Số trông như số” nhưng là character

Đây là lỗi rất hay gặp khi đọc CSV/Excel/API:

r
x <- c("10", "20", "3O")   # chữ O, không phải số 0
as.numeric(x)              # 10, 20, NA (warning)

Ops implication:

  • Nếu bạn ignore warning, bạn vừa đưa missingness “mới” vào pipeline.
  • Validate parse và fail-fast khi tỷ lệ parse fail vượt ngưỡng.

3.3 Logical coercion trong phép toán

r
TRUE + TRUE    # 2

Đôi khi là feature (đếm điều kiện), nhưng nhiều lúc là bug nếu bạn tưởng đang làm boolean logic.

⚠️ Cạm bẫy

Đừng dùng T/F. Chúng là biến bình thường và có thể bị override. Dùng TRUE/FALSE.

4) Attributes: class, names, dim (và pitfalls)

Attributes là metadata gắn lên object: names, dim, class, ...

4.1 names: identity của vector/list

r
v <- c(a = 10, b = 20)
names(v)    # "a" "b"
v["a"]      # giữ names

Pitfall: nhiều thao tác (combine/sort/subset) vẫn giữ names, làm “leak” identity không mong muốn vào output/report.

4.2 dim: thứ biến vector thành matrix/array

r
x <- 1:6
dim(x) <- c(2, 3)
is.matrix(x)    # TRUE

Pitfall: gắn dim sai khiến downstream code hiểu nhầm shape. Khi debug, kiểm tra:

  • dim(x)
  • length(x)

4.3 class: dispatch và “rớt class”

Ví dụ Date/POSIXct:

  • storage là double, nhưng class quyết định format/ops.

Pitfall phổ biến:

  • c(date1, date2) đôi khi rớt class (tùy cách combine).
  • as.numeric(Date) mất semantic “ngày”.

Checklist debug nhanh:

r
typeof(x)
class(x)
attributes(x)
str(x)

5) Production checklist: phòng bug trước khi nó thành incident

✅ Checklist triển khai

Guardrails tối thiểu

  • Validate types sau ingest (đừng đợi tới report)
  • Assert missingness policy (cột bắt buộc không được NA)
  • Không ignore warnings parse/coercion (tối thiểu log + đếm)
  • Kiểm tra class cho các cột có semantic mạnh (Date/datetime/factor)