如何在R中对每行数据应用if语句?解决DMS转十进制度报错
问题:紧凑DMS坐标转十进制度数时的条件判断报错
我有一组采用紧凑DMS格式的X坐标数据,需要转换为十进制度数,得先分离度、分、秒,但列中数字长度不一致(部分7位、部分8位),数据集示例:
coords$X <- c(100942.2, 67942.2, 229942.2, 239942.2, 52942.2)
我尝试用if else语句检查每个数字的长度,代码如下:
if (nchar(coords$X == 8)){0 coords$degrees.x <- as.numeric(str_sub(coords$X, 1, 2)) coords$min.x <- as.numeric(substr(coords$X, 3, 4)) coords$sec.x <- as.numeric(substr(coords$XC, 5, 7)) } else { coords$degrees.x <- as.numeric(str_sub(coords$X, 1, 1)) coords$min.x <- as.numeric(substr(coords$X, 2, 3)) coords$sec.x <- as.numeric(substr(coords$X, 4, 5)) }
但出现报错:
Error in if (nchar(coords$XCoordinatePlot == 8)) { : the condition has length > 1
需要解决这个问题,实现逐行应用条件判断。
解决方案
问题根源
if语句的局限性:基础if是标量判断,只能处理单个逻辑值,而coords$X是向量,nchar(coords$X) ==8会返回布尔向量,导致报错。- 逻辑表达式错误:原代码
nchar(coords$X == 8)是先判断数值是否等于8再取长度,完全不符合需求,正确写法是nchar(coords$X) ==8。 - 变量名笔误:代码中
substr(coords$XC, 5, 7)的XC是错误变量名,应为X。
方法1:向量化ifelse处理
用ifelse对向量每个元素做判断,替代标量if:
library(stringr) # 转字符串避免科学计数法干扰 coords$X_str <- as.character(coords$X) # 逐元素分离度分秒 coords$degrees.x <- ifelse(nchar(coords$X_str) == 8, as.numeric(str_sub(coords$X_str, 1, 2)), as.numeric(str_sub(coords$X_str, 1, 1))) coords$min.x <- ifelse(nchar(coords$X_str) == 8, as.numeric(str_sub(coords$X_str, 3, 4)), as.numeric(str_sub(coords$X_str, 2, 3))) coords$sec.x <- ifelse(nchar(coords$X_str) == 8, as.numeric(str_sub(coords$X_str, 5, 8)), # 包含小数部分 as.numeric(str_sub(coords$X_str, 4, 7))) # 转换为十进制度数 coords$X_decimal <- coords$degrees.x + coords$min.x/60 + coords$sec.x/3600
方法2:补前导零统一长度(更简洁鲁棒)
先给所有字符串补前导零至8位,直接截取固定位置,无需条件判断:
library(stringr) coords$X_str <- str_pad(as.character(coords$X), width = 8, side = "left", pad = "0") coords$degrees.x <- as.numeric(str_sub(coords$X_str, 1, 2)) coords$min.x <- as.numeric(str_sub(coords$X_str, 3, 4)) coords$sec.x <- as.numeric(str_sub(coords$X_str, 5, 8)) coords$X_decimal <- coords$degrees.x + coords$min.x/60 + coords$sec.x/3600
方法3:dplyr的case_when(适合数据框操作)
用tidyverse工具链的case_when清晰处理多条件:
library(dplyr) library(stringr) coords <- coords %>% mutate(X_str = as.character(X), degrees.x = case_when( nchar(X_str) ==8 ~ as.numeric(str_sub(X_str,1,2)), TRUE ~ as.numeric(str_sub(X_str,1,1)) ), min.x = case_when( nchar(X_str) ==8 ~ as.numeric(str_sub(X_str,3,4)), TRUE ~ as.numeric(str_sub(X_str,2,3)) ), sec.x = case_when( nchar(X_str) ==8 ~ as.numeric(str_sub(X_str,5,8)), TRUE ~ as.numeric(str_sub(X_str,4,7)) ), X_decimal = degrees.x + min.x/60 + sec.x/3600)
内容的提问来源于stack exchange,提问作者starski
相关产品推荐
相关产品推荐

