如何在R中编写函数按特定连续条件统计观测数及排障
解决你的决策树式统计问题与代码报错
首先,我们先拆解你的核心需求:你需要按指定列顺序,依次统计前一列取值为0时当前列取值为1的观测数,以此探究不同列顺序对决策树分支的影响,最后用ggplot2可视化对比结果。原代码的报错和逻辑偏差主要来自两个问题:一是函数逻辑不符合实际需求,二是未处理数据中的NA值。
1. 报错原因分析
你原函数count_no_yes是统计前i列全为1的观测数,完全偏离了“前一列0→当前列1”的统计需求;同时样本数据中存在全NA的列(比如AT列),这会导致apply计算时出现维度异常,触发dim(X) must have a positive length错误。
2. 完整解决方案代码
我们将从数据预处理、函数重定义、场景计算到绘图完整实现你的需求:
步骤1:数据预处理(处理NA值)
由于你的变量是0/1二值变量,我们将所有非第一列的NA替换为0(视为不满足条件),你也可以根据需求选择过滤含NA的观测:
# 将第2-16列的NA替换为0 data[, 2:16] <- lapply(data[, 2:16], function(x) ifelse(is.na(x), 0, x))
步骤2:定义符合需求的统计函数
根据你“决策树分支”的描述,我们提供两种函数供选择:
函数1:统计全局中「前一列0且当前列1」的观测数
适用于你需要统计所有观测中,顺序里上一列是0、当前列是1的数量:
count_prev0_curr1 <- function(data, col_order) { # 初始值为总观测数 counts <- c(nrow(data)) # 从第2列开始遍历顺序 for (i in 2:length(col_order)) { prev_col <- col_order[i-1] curr_col <- col_order[i] # 统计符合条件的观测数 cnt <- sum(data[[prev_col]] == 0 & data[[curr_col]] == 1, na.rm = TRUE) counts <- c(counts, cnt) } return(counts) }
函数2:统计决策树路径中「前面所有列0且当前列1」的观测数
更贴合决策树的路径筛选逻辑:统计经过前面所有列都为0的筛选后,当前列是1的观测数:
count_allprev0_curr1 <- function(data, col_order) { counts <- c(nrow(data)) # 初始筛选条件:保留所有观测 filter <- rep(TRUE, nrow(data)) for (i in 1:length(col_order)) { curr_col <- col_order[i] # 更新筛选条件:前面所有列都为0 if (i > 1) { filter <- filter & (data[[col_order[i-1]]] == 0) } # 统计当前筛选集合中当前列是1的数量 cnt <- sum(filter & (data[[curr_col]] == 1), na.rm = TRUE) counts <- c(counts, cnt) } return(counts) }
步骤3:计算两个场景的统计结果
# 场景A:原列顺序(第2到16列) orderA <- colnames(data)[2:16] countsA <- count_prev0_curr1(data, orderA) # 或选择count_allprev0_curr1 endpoints <- 0:(length(countsA)-1) scenarioA <- data.frame(endpoint = endpoints, hits = countsA, scenario = "scenarioA") # 场景B:自定义列顺序 orderB <- colnames(data)[c(9, 10, 11, 5, 6, 8, 3, 2, 4, 13, 12, 7, 14, 15, 16)] countsB <- count_prev0_curr1(data, orderB) # 对应选择相同函数 scenarioB <- data.frame(endpoint = endpoints, hits = countsB, scenario = "scenarioB") # 合并场景数据 scenarios <- rbind(scenarioA, scenarioB)
步骤4:用ggplot2绘制对比图
library(ggplot2) ggplot(scenarios, aes(x = endpoint, y = hits, color = scenario, group = scenario)) + geom_point(size = 2) + geom_line(linewidth = 1) + labs(title = "观测数随列顺序分支的变化", x = "步骤(0为初始总观测数)", y = "符合条件的观测数") + theme_minimal()
3. 关键注意事项
- NA值处理:如果需要过滤含NA的观测,可替换预处理步骤为
data <- na.omit(data),但会减少总观测数。 - 函数选择:根据你的实际需求选择对应函数,函数2更符合决策树的路径式筛选逻辑。
- 报错解决:新函数直接通过列索引访问数据,避免了
apply的维度问题,同时处理了NA值,不会再触发原报错。
内容的提问来源于stack exchange,提问作者Emilie




