循环索引值指定错误修复:index_1_i:index_2_i出现NA/NaN参数错误
问题描述
我尝试将数据集拆分为非重叠块,对每个块执行操作(如列乘以100)并保存结果。示例数据:
my_data = data.frame(id = 1:837, a = rnorm(837,100,100), b = rnorm(837,100,100), c = rnorm(837,100,100))
我想将其拆分为10个块:
res = round(seq(1, 837, by = 837/10))[-1] # [1] 85 168 252 336 420 503 587 671 754 res <- append(res, 1, after=0) res <- append(res, 837, after=10) # [1] 1 85 168 252 336 420 503 587 671 754 837
目标拆分方式:
- data_1 : id = 1 至 id = 84
- data_2: id = 85 至 id = 168
- data_3: id = 169 至 id = 251
- data_4 : id = 252 至 id = 335
- 以此类推
我编写了如下循环实现该过程:
for (i in 1:length(res)) { index_1_i = res[i] index_2_i = res[i+1] data_i = my_data[index_1_i : index_2_i,] data_i$a = data_i$a*100 data_i$b = data_i$b*100 - data_i$a*100 data_i$c = data_i$c*100 - data_i$b # 保存时文件名出现多余空格(例如"data_ 10.csv") write.csv(data_i, paste("data_", i, ".csv")) # 希望从R环境中删除对象以避免占用内存 data_i = NULL }
运行时出现错误:Error in index_1_i:index_2_i : NA/NaN argument
错误原因与修复方案
1. 循环边界越界(核心错误)
res向量长度是11,你循环时i从1到11,当i=11时,res[i+1]会调用res[12],超出向量范围返回NA,导致索引切片时出现无效参数。
修复:把循环范围改成1:(length(res)-1),这样i最大到10,res[i+1]刚好取到res[11](即837),不会越界。
2. 索引范围不符合目标拆分逻辑
当前代码里my_data[index_1_i : index_2_i,]会把第一个块变成1到85,但你要的是1到84。需要调整索引规则:
- 前9个块的结束索引是
res[i+1]-1 - 最后一个块直接用
res[i+1](避免把最后一行id=837漏掉)
修复:在循环里加判断逻辑:
if (i == length(res)-1) { data_i = my_data[index_1_i : index_2_i,] } else { data_i = my_data[index_1_i : (index_2_i - 1),] }
3. 文件名多余空格问题
paste("data_", i, ".csv")会自动在参数间加空格,改用paste0(无分隔符拼接)或者指定sep=""即可解决:
write.csv(data_i, paste0("data_", i, ".csv")) # 或者 write.csv(data_i, paste("data_", i, ".csv", sep=""))
4. 内存清理优化
赋值data_i = NULL可以,但用rm(data_i)更彻底,配合gc()触发垃圾回收(可选,内存紧张时推荐)。
修复后的完整代码
my_data = data.frame(id = 1:837, a = rnorm(837,100,100), b = rnorm(837,100,100), c = rnorm(837,100,100)) res = round(seq(1, 837, by = 837/10))[-1] res <- append(res, 1, after=0) res <- append(res, 837, after=10) # 修正循环范围 for (i in 1:(length(res)-1)) { index_1_i = res[i] index_2_i = res[i+1] # 调整索引匹配目标拆分 if (i == length(res)-1) { data_i = my_data[index_1_i : index_2_i,] } else { data_i = my_data[index_1_i : (index_2_i - 1),] } # 执行数据操作 data_i$a = data_i$a * 100 data_i$b = data_i$b * 100 - data_i$a * 100 data_i$c = data_i$c * 100 - data_i$b # 生成无空格的文件名并保存 write.csv(data_i, paste0("data_", i, ".csv"), row.names = FALSE) # 清理内存 rm(data_i) gc() }
额外优化建议
不想手动处理索引的话,可以用cut()生成分组标签,再用split()自动拆分,代码更简洁:
# 生成10个分组的标签 my_data$group = cut(my_data$id, breaks = res, labels = 1:10, include.lowest = TRUE) # 自动拆分数据为列表 data_list = split(my_data, my_data$group) # 遍历列表处理并保存 for (i in 1:length(data_list)) { df = data_list[[i]] df$a = df$a * 100 df$b = df$b * 100 - df$a * 100 df$c = df$c * 100 - df$b write.csv(df, paste0("data_", i, ".csv"), row.names = FALSE) rm(df) }
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

