Đây là một giải pháp sử dụng toán tử của data.table:=
, dựa trên câu trả lời của Andrie và Ramnath.
require(data.table) # v1.6.6
require(gdata) # v2.8.2
set.seed(1)
dt1 = create_dt(2e5, 200, 0.1)
dim(dt1)
[1] 200000 200 # more columns than Ramnath's answer which had 5 not 200
f_andrie = function(dt) remove_na(dt)
f_gdata = function(dt, un = 0) gdata::NAToUnknown(dt, un)
f_dowle = function(dt) { # see EDIT later for more elegant solution
na.replace = function(v,value=0) { v[is.na(v)] = value; v }
for (i in names(dt))
eval(parse(text=paste("dt[,",i,":=na.replace(",i,")]")))
}
system.time(a_gdata = f_gdata(dt1))
user system elapsed
18.805 12.301 134.985
system.time(a_andrie = f_andrie(dt1))
Error: cannot allocate vector of size 305.2 Mb
Timing stopped at: 14.541 7.764 68.285
system.time(f_dowle(dt1))
user system elapsed
7.452 4.144 19.590 # EDIT has faster than this
identical(a_gdata, dt1)
[1] TRUE
Lưu ý rằng f_dowle đã cập nhật dt1 theo tham chiếu. Nếu cần một bản sao cục bộ thì cần có một cuộc gọi rõ ràng đến copy
hàm để tạo một bản sao cục bộ của toàn bộ tập dữ liệu. của data.table setkey
, key<-
và :=
không sao chép-on-write.
Tiếp theo, hãy xem f_dowle đang dành thời gian ở đâu.
Rprof()
f_dowle(dt1)
Rprof(NULL)
summaryRprof()
$by.self
self.time self.pct total.time total.pct
"na.replace" 5.10 49.71 6.62 64.52
"[.data.table" 2.48 24.17 9.86 96.10
"is.na" 1.52 14.81 1.52 14.81
"gc" 0.22 2.14 0.22 2.14
"unique" 0.14 1.36 0.16 1.56
... snip ...
Ở đó, tôi sẽ tập trung vào na.replace
và is.na
, nơi có một vài bản sao vectơ và quét vectơ. Chúng có thể dễ dàng được loại bỏ bằng cách viết một hàm C nhỏ na.replace C cập nhật NA
bằng cách tham chiếu trong vectơ. Điều đó ít nhất sẽ giảm một nửa trong 20 giây tôi nghĩ. Có một chức năng như vậy tồn tại trong bất kỳ gói R?
Lý do f_andrie
thất bại có thể là vì nó sao chép toàn bộ dt1
hoặc tạo ra một ma trận logic lớn như toàn bộ dt1
, một vài lần. Hai phương thức khác hoạt động trên một cột tại một thời điểm (mặc dù tôi chỉ xem xét ngắn gọn NAToUnknown
).
EDIT (giải pháp thanh lịch hơn theo yêu cầu của Ramnath trong các bình luận):
f_dowle2 = function(DT) {
for (i in names(DT))
DT[is.na(get(i)), (i):=0]
}
system.time(f_dowle2(dt1))
user system elapsed
6.468 0.760 7.250 # faster, too
identical(a_gdata, dt1)
[1] TRUE
Tôi ước tôi đã làm theo cách đó để bắt đầu!
EDIT2 (hơn 1 năm sau, bây giờ)
Cũng có set()
. Điều này có thể nhanh hơn nếu có rất nhiều cột được lặp qua, vì nó tránh được chi phí (nhỏ) của cuộc gọi [,:=,]
trong một vòng lặp. set
là một vòng lặp :=
. Xem ?set
.
f_dowle3 = function(DT) {
# either of the following for loops
# by name :
for (j in names(DT))
set(DT,which(is.na(DT[[j]])),j,0)
# or by number (slightly faster than by name) :
for (j in seq_len(ncol(DT)))
set(DT,which(is.na(DT[[j]])),j,0)
}
data.table
thành adata.frame
? Adata.table
là mộtdata.frame
. Bất kỳ hoạt động data.frame sẽ chỉ hoạt động.