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

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

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:

  1. 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:

  1. if (nchar(coords$X == 8)){
  2. coords$degrees.x <- as.numeric(str_sub(coords$X, 1, 2))
  3. coords$min.x <- as.numeric(substr(coords$X, 3, 4))
  4. coords$sec.x <- as.numeric(substr(coords$XC, 5, 7))
  5. } else {
  6. coords$degrees.x <- as.numeric(str_sub(coords$X, 1, 1))
  7. coords$min.x <- as.numeric(substr(coords$X, 2, 3))
  8. coords$sec.x <- as.numeric(substr(coords$X, 4, 5))
  9. }

But I am getting an error:

  1. Error in if (nchar(coords$XCoordinatePlot == 8)) { :
  2. 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:

  1. 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:

  1. if (nchar(coords$X == 8)){0
  2. coords$degrees.x <- as.numeric(str_sub(coords$X, 1, 2))
  3. coords$min.x <- as.numeric(substr(coords$X, 3, 4))
  4. coords$sec.x <- as.numeric(substr(coords$XC, 5, 7))
  5. } else {
  6. coords$degrees.x <- as.numeric(str_sub(coords$X, 1, 1))
  7. coords$min.x <- as.numeric(substr(coords$X, 2, 3))
  8. coords$sec.x <- as.numeric(substr(coords$X, 4, 5))
  9. }

But I am getting an error:

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

Is there a way to make this work?

答案1

得分: 2

Sure, here is the translated code:

  1. 像这样吗?使用 `sprintf` 使所有数字具有相同的长度,然后获取子字符串。
  2. 注意:下面的函数会丢弃小数部分。
  3. X <- c(100942.2, 67942.2, 229942.2, 239942.2, 52942.2)
  4. fun <- function(x) {
  5. y <- sprintf("%06d", as.integer(x))
  6. D <- as.integer(substr(y, 1, 2))
  7. M <- as.integer(substr(y, 3, 4))
  8. S <- as.integer(substr(y, 5, 6))
  9. cbind(D, M, S)
  10. }
  11. fun(X)
  12. #> D M S
  13. #> [1,] 10 9 42
  14. #> [2,] 6 79 42
  15. #> [3,] 22 99 42
  16. #> [4,] 23 99 42
  17. #> [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.

  1. X &lt;- c(100942.2, 67942.2, 229942.2, 239942.2, 52942.2)
  2. fun &lt;- function(x) {
  3. y &lt;- sprintf(&quot;%06d&quot;, as.integer(x))
  4. D &lt;- as.integer(substr(y, 1, 2))
  5. M &lt;- as.integer(substr(y, 3, 4))
  6. S &lt;- as.integer(substr(y, 5, 6))
  7. cbind(D, M, S)
  8. }
  9. fun(X)
  10. #&gt; D M S
  11. #&gt; [1,] 10 9 42
  12. #&gt; [2,] 6 79 42
  13. #&gt; [3,] 22 99 42
  14. #&gt; [4,] 23 99 42
  15. #&gt; [5,] 5 29 42

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

答案2

得分: 2

以下是翻译好的部分:

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

  1. coords$degrees <- coords$X %/% 10000
  2. coords$min <- (coords$X %% 10000) %/% 100
  3. coords$sec <- coords$X %% 100

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

  1. library(purrr)
  2. library(stringr)
  3. convert <- function(x) {
  4. if (nchar(x) == 8){
  5. degrees <- as.numeric(str_sub(x, 1, 2))
  6. min <- as.numeric(substr(x, 3, 4))
  7. sec <- as.numeric(substr(x, 5, 7))
  8. } else {
  9. degrees <- as.numeric(str_sub(x, 1, 1))
  10. min <- as.numeric(substr(x, 2, 3))
  11. sec <- as.numeric(substr(x, 4, 5))
  12. }
  13. return(data.frame(degrees, min, sec))
  14. }
  15. 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:

  1. coords$degrees &lt;- coords$X %/% 10000
  2. coords$min &lt;- (coords$X %% 10000) %/% 100
  3. 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:

  1. library(purrr)
  2. library(stringr)
  3. convert &lt;- function(x) {
  4. if (nchar(x) == 8){
  5. degrees &lt;- as.numeric(str_sub(x, 1, 2))
  6. min &lt;- as.numeric(substr(x, 3, 4))
  7. sec &lt;- as.numeric(substr(x, 5, 7))
  8. } else {
  9. degrees &lt;- as.numeric(str_sub(x, 1, 1))
  10. min &lt;- as.numeric(substr(x, 2, 3))
  11. sec &lt;- as.numeric(substr(x, 4, 5))
  12. }
  13. return(data.frame(degrees, min, sec))
  14. }
  15. 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:

确定