【问题标题】:Converting Character to Numeric without NA Coercion in R在R中将字符转换为没有NA强制的数字
【发布时间】:2013-07-09 23:58:30
【问题描述】:

我在 R 中工作,有一个数据框 dd_2006,带有数字向量。当我第一次导入数据时,我需要从我的三个变量中删除 $、小数点和一些空格:SumOfCost、SumOfCases 和 SumOfUnits。为此,我使用了str_replace_all。但是,一旦我使用了str_replace_all,向量就会被转换为字符。所以我使用 as.numeric(var) 将向量转换为数字,但是引入了 NA,即使在我运行 as.numeric 代码之前运行下面的代码时,向量中也没有 NA。

sum(is.na(dd_2006$SumOfCost))
[1] 0
sum(is.na(dd_2006$SumOfCases))
[1] 0
sum(is.na(dd_2006$SumOfUnits))
[1] 0

这是我导入后的代码,从向量中删除 $ 开始。在str(dd_2006) 输出中,为了空间,我删除了一些变量,所以下面str_replace_all 代码中的#s 列与我在此处发布的输出不匹配(但它们在原始代码中匹配) ):

library("stringr")
dd_2006$SumOfCost <- str_sub(dd_2006$SumOfCost, 2, ) #2=the first # after the $

#Removes decimal pt, zero's after, and commas
dd_2006[ ,9] <- str_replace_all(dd_2006[ ,9], ".00", "")
dd_2006[,9] <- str_replace_all(dd_2006[,9], ",", "")

dd_2006[ ,10] <- str_replace_all(dd_2006[ ,10], ".00", "")
dd_2006[ ,10] <- str_replace_all(dd_2006[,10], ",", "")

dd_2006[ ,11] <- str_replace_all(dd_2006[ ,11], ".00", "")
dd_2006[,11] <- str_replace_all(dd_2006[,11], ",", "")

str(dd_2006)
'data.frame':   12604 obs. of  14 variables:
 $ CMHSP                     : Factor w/ 46 levels "Allegan","AuSable Valley",..: 1 1 1
 $ FY                        : Factor w/ 1 level "2006": 1 1 1 1 1 1 1 1 1 1 ...
 $ Population                : Factor w/ 1 level "DD": 1 1 1 1 1 1 1 1 1 1 ...
 $ SumOfCases                : chr  "0" "1" "0" "0" ...
 $ SumOfUnits                : chr  "0" "365" "0" "0" ...
 $ SumOfCost                 : chr  "0" "96416" "0" "0" ...

我找到了一个与我的here 类似的问题的回复,使用以下代码:

# create dummy data.frame
d <- data.frame(char = letters[1:5], 
                fake_char = as.character(1:5), 
                fac = factor(1:5), 
                char_fac = factor(letters[1:5]), 
                num = 1:5, stringsAsFactors = FALSE)

让我们看一下data.frame

> d
  char fake_char fac char_fac num
1    a         1   1        a   1
2    b         2   2        b   2
3    c         3   3        c   3
4    d         4   4        d   4
5    e         5   5        e   5

让我们运行:

> sapply(d, mode)
       char   fake_char         fac    char_fac         num 
"character" "character"   "numeric"   "numeric"   "numeric" 
> sapply(d, class)
       char   fake_char         fac    char_fac         num 
"character" "character"    "factor"    "factor"   "integer" 

现在您可能会问自己“异常在哪里?”好吧,我在 R 中遇到了一些很奇怪的东西,这不是最令人困惑的事情,但它会让你感到困惑,尤其是如果你在上床睡觉之前阅读了这篇文章。

这里是:前两列是字符。我故意称第二个 fake_char。找出这个字符变量与 Dirk 在他的回复中创建的字符变量的相似性。它实际上是一个转换为字符的数值向量。第 3 和第 4 列是因子,最后一列是“纯”数字。

如果你使用转换函数,你可以将 fake_char 转换为数字,但不能将 char 变量本身。

> transform(d, char = as.numeric(char))
  char fake_char fac char_fac num
1   NA         1   1        a   1
2   NA         2   2        b   2
3   NA         3   3        c   3
4   NA         4   4        d   4
5   NA         5   5        e   5
Warning message:
In eval(expr, envir, enclos) : NAs introduced by coercion
but if you do same thing on fake_char and char_fac, you'll be lucky, and get away with no NA's:

transform(d, fake_char = as.numeric(fake_char), char_fac = as.numeric(char_fac))

  char fake_char fac char_fac num
1    a         1   1        1   1
2    b         2   2        2   2
3    c         3   3        3   3
4    d         4   4        4   4
5    e         5   5        5   5

所以我在我的脚本中尝试了上面的代码,但仍然想出了 NA(没有关于强制的警告消息)。

#changing sumofcases, cost, and units to numeric
dd_2006_1 <- transform(dd_2006, SumOfCases = as.numeric(SumOfCases), SumOfUnits = as.numeric(SumOfUnits), SumOfCost = as.numeric(SumOfCost))

> sum(is.na(dd_2006_1$SumOfCost))
[1] 12
> sum(is.na(dd_2006_1$SumOfCases))
[1] 7
> sum(is.na(dd_2006_1$SumOfUnits))
[1] 11

我还使用table(dd_2006$SumOfCases) 等来查看观察结果,看看我在观察结果中是否遗漏了任何字符,但没有。关于为什么会出现 NA 以及如何摆脱它们的任何想法?

【问题讨论】:

  • 抱歉,请问有什么问题?链接的答案似乎很好地总结了所有内容,并且没有 you 实际面临的问题的可重现示例,我不确定其他人如何提供帮助....
  • 我猜这些数据来自 Excel 或其他电子表格。下次,请在导出前清除所有格式。

标签: r vector character numeric na


【解决方案1】:

一个简单的解决方案是让retype 猜测每一列的新数据类型

library(dplyr)
library(hablar)

dd_2006 %>% retype()

【讨论】:

    【解决方案2】:

    如果您也想将字符转换为数字,则首先将其转换为因子(使用 as.factor)并保存/覆盖现有变量。接下来将此因子变量转换为数字(使用 as.numeric)。您不会以这种方式创建 NA,并且能够将您拥有的数据集转换为数字。

    【讨论】:

    • as.numeric(as.factor(df$x)) 只是将值替换为 1 和 2,索引
    【解决方案3】:

    正如 Anando 指出的那样,问题出在您的数据中,如果没有可重现的示例,我们无法真正帮助您。也就是说,这里有一个代码 sn-p 可帮助您确定数据中导致问题的记录:

    test = as.character(c(1,2,3,4,'M'))
    v = as.numeric(test) # NAs intorduced by coercion
    ix.na = is.na(v)
    which(ix.na) # row index of our problem = 5
    test[ix.na]  # shows the problematic record, "M"
    

    与其猜测引入 NA 的原因,不如提取导致问题的记录并直接/单独处理它们,直到 NA 消失。

    更新:看起来问题出在您对str_replace_all 的调用中。我不知道 stringr 库,但我认为您可以像这样使用 gsub 完成同样的事情:

    v2 = c("1.00","2.00","3.00")
    gsub("\\.00", "", v2)
    
    [1] "1" "2" "3"
    

    我不完全确定这会完成什么:

    sum(as.numeric(v2)!=as.numeric(gsub("\\.00", "", v2))) # Illustrate that vectors are equivalent.
    
    [1] 0
    

    除非这为您实现了某些特定目的,否则我建议您完全从预处理中删除这一步,因为它似乎没有必要并且似乎会给您带来问题。

    【讨论】:

    • 当我为 SumOfUnits 运行该代码时,我得到 &gt; which(ix.na) #row index of problem NAs [1] 1098 2297 4728 5559 5592 5702 6955 8191 10517 10881 10955 &gt; test[ix.na] # [1] "" "" "" "" "" "" "" "" "" "" "" 但是当我查看原始数据集中的那些行时,它看起来像这样:SumOfUnits 800.00 0.00 100.00 100.00 100.00 300.00 400.00 200.00 200.00 600.00 100.00 那么数据有什么问题相反,当我运行 str_replace_all 代码时发生了什么?
    • 看起来你解决了这个问题。我真的不知道预处理这些字符串会完成什么,因为您可以将这些值转换为数字,无论有无小数,但我在更新的答案中使用gsub 说明了另一种解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    • 2014-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多