R语言:为数据框非0值添加占比,排除0值的实现问题
问题:仅为数据框非0数值添加占比,0值保持原样
数据集
response <- c("Best overall response", "Best overall response", "Best overall response", "Disease control(c)", "Disease control(c)", "Observed response(b)", "Observed response(b)") value <- c("Partial Response", "Progressive Disease", "Stable Disease", "No", "Yes", "No", "Yes") drug1 <- c(0, 3, 2, 3, 2, 5, 0) drug2 <- c(0, 3, 1, 3, 1, 4, 0) drug3 <- c(0, 1, 3, 1, 3, 4, 0) drug4 <- c(0, 2, 1, 2, 1, 3, 0) drug5 <- c(1, 0, 2, 0, 3, 2, 1) zero_ex_df <- data.frame(response, value) zero_ex_df <- data.frame(zero_ex_df, drug1) zero_ex_df <- data.frame(zero_ex_df, drug2) zero_ex_df <- data.frame(zero_ex_df, drug3) zero_ex_df <- data.frame(zero_ex_df, drug4) zero_ex_df <- data.frame(zero_ex_df, drug5)
初始代码(为所有数值添加占比)
该代码会给所有数值(包括0)添加占比,不符合需求:
cnt <- 2 ### empty dataframe df <- data.frame() ### for every instance in esc_table_df_cast besides the first 2 non numeric columns ... for (i in zero_ex_df[3:length(zero_ex_df)]) { ### increase count cnt <- cnt + 1 ### create new varible that totals sum of every column and divides by 3 (since this will always give us the sample size) and divides by the current number and mutiplies by 100 to get a percentage. sprintf if for formatting it adds the % symbol and rounds to 1 decimal new <- (sprintf("(%0.1f%%)", (i / (sum(zero_ex_df[cnt]) / 3) * 100))) ### pasting the percentage next to the number and appending to empty dataframe df <- rbind(df, (paste0(i, new))) } ## transposing data frame df <- t(df) zero_ex_df[3:length(zero_ex_df)] <- df
错误的修改尝试
尝试添加条件判断仅处理非0值,但因逻辑错误未得到正确结果:
cnt <- 2 df <- data.frame() for (i in zero_ex_df[3:length(zero_ex_df)]) { if (i == 0){ new1 <- i df <- rbind(df, new1) } else { cnt <- cnt + 1 new <- (sprintf("(%0.1f%%)", (i / (sum(zero_ex_df[cnt]) / 3) * 100))) df <- rbind(df, (paste0(i, new))) } } df <- t(df) zero_ex_df[3:length(zero_ex_df)] <- df
错误原因分析
- 条件判断逻辑错误:
if (i == 0)是对整个列进行判断,而非列中的单个元素,只有当整列全为0时才会执行if分支,否则所有元素都走else分支。 - cnt计数逻辑错误:仅在else分支递增cnt,导致后续列的分母计算时索引错位,占比结果错误。
正确实现方法
方法1:修正循环逻辑
使用向量操作ifelse对列中每个元素单独判断,同时保证cnt在每次循环都正确递增:
cnt <- 2 df <- data.frame() # 遍历所有drug列 for (col in zero_ex_df[3:length(zero_ex_df)]) { cnt <- cnt + 1 # 计算当前列的占比分母(样本量) denominator <- sum(col) / 3 # 对每个元素判断:0则保留原值,非0则拼接占比 processed_col <- ifelse(col == 0, as.character(col), paste0(col, sprintf("(%0.1f%%)", (col / denominator) * 100))) # 将处理后的列加入临时数据框 df <- rbind(df, processed_col) } # 转置后替换原数据框的drug列 df <- t(df) zero_ex_df[3:length(zero_ex_df)] <- df
方法2:使用dplyr简化实现(推荐)
利用dplyr的across函数批量处理列,代码更简洁高效:
library(dplyr) zero_ex_df <- zero_ex_df %>% mutate( across( starts_with("drug"), # 匹配所有以drug开头的列 ~ ifelse(.x == 0, as.character(.x), paste0(.x, sprintf("(%0.1f%%)", (.x / (sum(.x)/3)) * 100))) ) )
内容的提问来源于stack exchange,提问作者samthecodegod
相关产品推荐
相关产品推荐

