how to determine if a character vector is a valid numeric or integer vector

☆樱花仙子☆ 提交于 2019-11-30 17:19:52
josliber

As discussed here, checking if as.numeric returns NA values is a simple approach to checking if a character string contains numeric data. Now you can do something like:

myDF2 <- lapply(myDF, function(col) {
  if (suppressWarnings(all(!is.na(as.numeric(as.character(col)))))) {
    as.numeric(as.character(col))
  } else {
    col
  }
})
str(myDF2)
# List of 3
#  $ w  : num [1:2] 1 2
#  $ x.y: num [1:2] 0.1 0.2
#  $ x.z: Factor w/ 2 levels "cat","dog": 1 2

When NAs are included @josliber's function won't work (though it answers the question well for the sample data). @Amy M's function should work but requires loading Hmisc package.

What about something like this:

can.be.numeric <- function(x) {
    stopifnot(is.atomic(x) || is.list(x)) # check if x is a vector
    numNAs <- sum(is.na(x))
    numNAs_new <- suppressWarnings(sum(is.na(as.numeric(x))))
    return(numNAs_new == numNAs)
}

It counts NAs in input vector and NAs in the output of as.numeric() and returns TRUE if the vector can be "safely" converted to numeric (i.e. without adding any additional NA values).

You can use plyr::ldply:

ldply(myList,.fun=function(x)data.frame(x))

      .id w x.y x.z
1 object1 1 0.1 cat
2 object2 2 0.2 dog

I don't see any advantage of plyr::ldply over regular base R methods:

 do.call(rbind, lapply(myList, data.frame) )
#-------------

        w x.y x.z
object1 1 0.1 cat
object2 2 0.2 dog

The trouble was arising because of a misguided attempt to "flatten" the data without consideration for it's intrinsic structure.

If you just want to convert all-numeric vectors that have been erroneously classed as character when they were read in, you can also use the function all.is.numeric from the Hmisc package:

myDF2 <- lapply(myDF, Hmisc::all.is.numeric, what = "vector", extras = NA)

Choosing what = "vector" will convert the vector to numeric if it only contains numbers. NAs or other types of missing values will prevent conversion unless they are specified in the extras argument as above.

Note however that if applied to a whole data.frame containing Date or POSIXct vectors, these will also be converted to numeric. To prevent this you can wrap it in a function as below:

catchNumeric <- function(dtcol) {
  require(Hmisc)
  if (is.character(dtcol)) {
    dtcol1 = all.is.numeric(dtcol, what = "vector", extras = NA)
  } else {
    dtcol1 = dtcol
  }
  return(dtcol1)
}

Then apply to your data.frame:

myDF2 <- lapply(myDF, catchNumeric)

If you have a list or a vector with strings and you want to convert only the numbers to numeric, a possible solution is:

catchNumeric <- function(mylist) {
  newlist <- suppressWarnings(as.numeric(mylist))
  mylist <- as.list(mylist)
  mylist[!is.na(newlist)] <- newlist[!is.na(newlist)]
  mylist
}

> catchNumeric(c("123", "c12", "abc", "123.12"))
[[1]]
[1] 123

[[2]]
[1] "c12"

[[3]]
[1] "abc"

[[4]]
[1] 123.12

> catchNumeric(list("123", "c12", "abc", "123.12"))
[[1]]
[1] 123

[[2]]
[1] "c12"

[[3]]
[1] "abc"

[[4]]
[1] 123.12
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!