如何在Arrow中无需加载全量数据删除行并更新磁盘数据集?
用Arrow处理超大数据集:不加载内存删除行并更新磁盘
首先要明确:open_dataset返回的是Dataset对象,不是普通数据框,所以不能用行索引直接切片(比如arr[!remove_rows,]);而且超大数据集下nrow(arr)会触发全量数据扫描加载到内存,完全违背我们的初衷。下面是正确的处理流程:
核心思路
利用Arrow的延迟计算特性,所有过滤操作在磁盘层面执行,不会把全量数据加载到内存;通过随机标记或概率筛选的方式删除指定行数,最后将结果写入磁盘(推荐先写临时目录再替换原目录,避免数据丢失)。
具体代码实现
library(arrow) # 原数据集路径 path <- "C:\\Users\\....\\Desktop\\my_data" # (如果已经写入过数据集,可跳过这一步) write_dataset(dataset = iris, path = path, partitioning = "Species") # 打开磁盘上的数据集(不加载到内存) arr <- open_dataset(path) # -------------------------- # 方式1:适合已知总行数的场景(小数据集示例) # 注意:超大数据集不建议用这种方式,因为row_number()会触发全局排序 # -------------------------- # 给每行添加唯一行号,筛选掉指定行 filtered_ds <- arr %>% mutate(row_id = row_number()) %>% # 延迟计算,不加载数据 filter(!(row_id %in% !!sample(1:150, 50))) %>% # 筛选掉随机抽取的50行 select(-row_id) # 移除临时行号列 # -------------------------- # 方式2:适合超大数据集(无需提前知道总行数) # -------------------------- # 生成0-1的随机数,通过概率筛选保留目标行数(比如iris共150行,要保留100行,概率设为100/150≈0.666) target_keep_ratio <- (nrow(iris) - 50)/nrow(iris) # 大数据集可直接设比例,比如0.7 filtered_ds <- arr %>% mutate(rand = random()) %>% # 生成随机数,延迟计算 filter(rand > (1 - target_keep_ratio)) %>% # 筛选掉随机数较小的50行 select(-rand) # 移除临时随机列 # -------------------------- # 将过滤后的数据集写入磁盘(安全方案) # -------------------------- # 先写入临时目录,避免覆盖原数据时出错丢失数据 temp_path <- "C:\\Users\\....\\Desktop\\my_data_temp" write_dataset( filtered_ds, path = temp_path, partitioning = "Species", delete_existing = TRUE # 若临时目录已存在则删除 ) # 替换原目录(Windows下需先删除原目录,再重命名临时目录) unlink(path, recursive = TRUE) file.rename(temp_path, path)
关键注意事项
- 延迟计算:Arrow的
mutate()、filter()都是延迟执行的,只有调用write_dataset时才会实际扫描磁盘数据并执行计算,全程不会加载全量数据到内存。 - 避免全量扫描:超大数据集绝对不要用
nrow(arr),这会强制把所有数据加载到内存统计行数,改用概率筛选的方式更高效。 - 数据安全:直接覆盖原目录风险高,建议先写入临时目录,确认数据无误后再替换原目录。
- 分区保持:如果原数据集是分区的(比如按Species分区),
write_dataset会自动保持相同的分区结构。
内容的提问来源于stack exchange,提问作者mr.T
相关产品推荐
相关产品推荐

