如何在R中对每一行单独应用if语句?

huangapple go评论73阅读模式
英文:

How to apply an if statement on each individual row in R?

问题

I have a datasets of X and Y coordinates that are in packed DMS format and I want to transform them to decimal degrees. To do that I have to separate the degrees, minutes and seconds. It would be straightforward if all the numbers in the column had the same length, but some have 7 and some 8.
The data set looks something like this:

coords$X <- c(100942.2, 67942.2, 229942.2, 239942.2, 52942.2)

I had the idea to use an if else statement to check the length of each number using this code:

if (nchar(coords$X == 8)){
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))
}

But I am getting an error:

Error in if (nchar(coords$XCoordinatePlot == 8)) { : 
  the condition has length > 1

Is there a way to make this work?

英文:

I have a datasets of X and Y coordinates that are in packed DMS format and I want to transform them to decimal degrees. To do that I have to separate the degrees, minutes and seconds. It would be straightforward if all the numbers in the column had the same length, but some have 7 and some 8.
The data set looks something like this:

coords$X <- c(100942.2, 67942.2, 229942.2, 239942.2, 52942.2)

I had the idea to use an if else statement to check the length of each number using this code:

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))
}

But I am getting an error:

Error in if (nchar(coords$XCoordinatePlot == 8)) { : 
  the condition has length > 1

Is there a way to make this work?

答案1

得分: 2

Sure, here is the translated code:

像这样吗?使用 `sprintf` 使所有数字具有相同的长度,然后获取子字符串。
注意:下面的函数会丢弃小数部分。

X <- c(100942.2, 67942.2, 229942.2, 239942.2, 52942.2)

fun <- function(x) {
  y <- sprintf("%06d", as.integer(x))
  D <- as.integer(substr(y, 1, 2))
  M <- as.integer(substr(y, 3, 4))
  S <- as.integer(substr(y, 5, 6))
  cbind(D, M, S)
}

fun(X)
#>       D  M  S
#> [1,] 10  9 42
#> [2,]  6 79 42
#> [3,] 22 99 42
#> [4,] 23 99 42
#> [5,]  5 29 42

在 2023-04-13 创建,使用 reprex v2.0.2

英文:

Something like this? Use sprintf to have all numbers of the same length, then get the substrings.
Note: The function below discards the decimal part.

X &lt;- c(100942.2, 67942.2, 229942.2, 239942.2, 52942.2)

fun &lt;- function(x) {
  y &lt;- sprintf(&quot;%06d&quot;, as.integer(x))
  D &lt;- as.integer(substr(y, 1, 2))
  M &lt;- as.integer(substr(y, 3, 4))
  S &lt;- as.integer(substr(y, 5, 6))
  cbind(D, M, S)
}

fun(X)
#&gt;       D  M  S
#&gt; [1,] 10  9 42
#&gt; [2,]  6 79 42
#&gt; [3,] 22 99 42
#&gt; [4,] 23 99 42
#&gt; [5,]  5 29 42

<sup>Created on 2023-04-13 with reprex v2.0.2</sup>

答案2

得分: 2

以下是翻译好的部分:

有多种可能的方法可以转换这些数据。我认为最好的方法是使用除法和余数:

coords$degrees <- coords$X %/% 10000
coords$min <- (coords$X %% 10000) %/% 100
coords$sec <- coords$X %% 100

如果您想使用if/else语句,您可以将它放在一个函数内,并使用purrr包中的map_df()将其应用于每个元素:

library(purrr)
library(stringr)

convert <- function(x) {
  if (nchar(x) == 8){
    degrees <- as.numeric(str_sub(x, 1, 2))
    min <- as.numeric(substr(x, 3, 4))
    sec <- as.numeric(substr(x, 5, 7))
  } else {
    degrees <- as.numeric(str_sub(x, 1, 1))
    min <- as.numeric(substr(x, 2, 3))
    sec <- as.numeric(substr(x, 4, 5))
  }

  return(data.frame(degrees, min, sec))
}

cbind(coords, map_df(coords$X, convert))

(请注意,您的函数不会四舍五入,而是去除秒的小数部分。)

英文:

There are multiple possible ways to convert these data. The best way in my opinion would be to use division and remainders:

coords$degrees &lt;- coords$X %/% 10000
coords$min &lt;- (coords$X %% 10000) %/% 100
coords$sec &lt;- coords$X %% 100

If you want to use your if/else statement, you could place it inside a function and use map_df() from the package purrr to apply it to each element:

library(purrr)
library(stringr)

convert &lt;- function(x) {
  if (nchar(x) == 8){
    degrees &lt;- as.numeric(str_sub(x, 1, 2))
    min &lt;- as.numeric(substr(x, 3, 4))
    sec &lt;- as.numeric(substr(x, 5, 7))
  } else {
    degrees &lt;- as.numeric(str_sub(x, 1, 1))
    min &lt;- as.numeric(substr(x, 2, 3))
    sec &lt;- as.numeric(substr(x, 4, 5))
  }

  return(data.frame(degrees, min, sec))
}

cbind(coords, map_df(coords$X, convert))

(Note that your function does not round but strip the decimal of secs.)

huangapple
  • 本文由 发表于 2023年4月13日 14:49:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76002430.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定