【问题标题】:R - Cannot change NAs in Data Frame to numericR - 无法将数据框中的 NA 更改为数字
【发布时间】:2016-12-15 18:05:55
【问题描述】:

我有一个名为“游戏”的值数据框,其中包含几列数字。原始的 csv 文件有一些缺失的值,当我读入它们时它们变成了 NA。我试图用行中位数(已经存储为数据框的列)替换这些 NA。我无法让原始 NA 从字符强制转换为数字。

我首先找到了缺失值的索引。

ng <- which(is.na(games), arr.ind = TRUE)

然后我尝试用“linemedian”列中的值替换 NA。

games[ng] <- games[ng[,1], "linemedian"]
games[ng]
[1] " -3.25" "  9.98" " -9.1"  " -9.1"  " 14.0"  " -3.25" "  9.98" " -3.25" "  9.98" "  2.30" " 13.75" "-24.00" "  3.71" " 15.94" " 14.25" " -9.83" " 13.75" " -4.88"

用任意数字替换 NA 也不起作用。

games[is.na(games)] <- 0
[1] "  0.0"  "  0.0"  "  0"    "  0"    "  0"    "  0.0"  "  0.0"  "  0.0"  "  0.0"  "  0.00" "  0.00" "  0.00" "  0"    "  0"    "  0.00" "  0.00" "  0.00" "  0.00"

我认为删除空格可能会改变结果,但事实并非如此。

games[ng] <- as.numeric(trimws(games[ng[,1], "linemedian"]))
[1] "-3.25" "9.98"  "-9.1"  "-9.1"  "14"    "-3.25" "9.98"  "-3.25" "9.98"  "2.3"   "13.75" "-24"   "3.71"  "15.94" "14.25" "-9.83" "13.75" "-4.88"

其他无效的尝试:

games[ng] <- type.convert(games[ng]) # using type.convert()

games[, -c(1,2)] <- as.numeric(games[, -c(1,2)]) # first two columns are metadata
Error: (list) object cannot be coerced to type 'double'

games[, -c(1,2)] <- as.numeric(unlist(games[, -c(1,2)]))    

games[ng] <- as.numeric(as.character(trimws(games[ng[,1], "linemedian"])))

# New Addition from Answer
games[, sapply(games, is.numeric)][ng] <- games[, sapply(games, is.numeric)][ng[,1], "linemedian"]

我确定我分配给 games[ng] 的值是一个数字。

games[ng[,1], "linemedian"]
[1]  -3.25   9.98  -9.10  -9.10  14.00  -3.25   9.98  -3.25   9.98   2.30  13.75 -24.00   3.71  15.94  14.25  -9.83  13.75  -4.88
typeof(games[ng[,1], "linemedian"])
[1] "double"

我在 Stack Overflow 板上的任何地方,显而易见的答案应该是 games[is.na(games)]

如果你想复制,这里是完整的代码:

## Download Raw Files

download.file("http://www.thepredictiontracker.com/ncaa2016.csv",
          "data/ncaa2016.csv")

download.file("http://www.thepredictiontracker.com/ncaapredictions.csv",
          "data/ncaapredictions.csv")

## Create Training and Prediction Data Sets

games <- read.csv("data/ncaa2016.csv", header = TRUE, stringsAsFactors = FALSE, 
              colClasses=c(rep("character",2),rep("numeric",72)))

preds <- read.csv("data/ncaapredictions.csv", header = TRUE, stringsAsFactors = TRUE)
colnames(preds)[colnames(preds) == "linebillings"] <- "linebill"
colnames(preds)[colnames(preds) == "linebillings2"] <- "linebill2"
colnames(preds)[colnames(preds) == "home"] <- "Home"
colnames(preds)[colnames(preds) == "road"] <- "Road"

## Remove Columns with too many missing values

rm <- unique(c(names(games[, sapply(games, function(z) sum(is.na(z))) > 50]), # Games and predictions
           names(preds[, sapply(preds, function(z) sum(is.na(z))) > 10]))) # with missing data

games <- games[, !(names(games) %in% rm)] # Remove games with no prediction data 

preds <- preds[, !(names(preds) %in% rm)] # Remove predictions with no game data 

## Replace NAs with Prediction Median
ng <- which(is.na(games), arr.ind = TRUE)
games[ng] <- games[ng[,1], "linemedian"]

另外,我不能发布整个 dput() 输出,但这里有一些数据集只是为了显示结构。

dput(head(games[1:6]))

structure(list(Home = c("Alabama", "Arizona", "Arkansas", "Arkansas St.", 
"Auburn", "Boston College"), Road = c("USC", "BYU", "Louisiana Tech", 
"Toledo", "Clemson", "Georgia Tech"), line = c("12", "-2", "24.5", 
"4", "-8.5", "-3"), linesag = c(12.19, 0.97, 24.26, -2.07, -4.78, 
-2.74), linepayne = c(12, -0.81, 12.53, -0.86, -10.72, -3.87), 
linemassey = c(19.15, -2.1, 21.07, -8.68, -5.45, -6.76)), .Names = c("Home", 
"Road", "line", "linesag", "linepayne", "linemassey"), row.names = c(NA, 
6L), class = "data.frame")

最后,我在 x86_64-w64-mingw32 上运行 R 版本 3.2.1。

【问题讨论】:

  • 您需要在games 的合适子集上发布调用dput 的结果,以便人们可以看到数据结构是什么。
  • 我认为我们都将该输出误解为表示 games 中的值是字符。我会发布一些调试代码。

标签: r


【解决方案1】:

如果没有测试用例,这将是未经测试的。看来您正在获得全局替换,但由于您的某些列是字符,您会强制转换为从 0 强制转换的所有字符值。我可能曾尝试将过程限制为仅数字列:

games[ , sapply(games, is.numeric) ][ ng ] <- 
                        games[ , sapply(games, is.numeric)][ng[,1], "linemedian"]

修改您几乎可重现的代码后,我得出结论,您的原始代码是成功的,但您检查的输出是问题区域>

 str( games[ , sapply(games, is.numeric)][ng[,1], "linemedian"] )
#num [1:23] -3.25 9.98 -9.1 -9.1 14 -3.25 9.98 -3.25 9.98 2.3 ...

 games[ ng ] <- 
                         games[ , sapply(games, is.numeric)][ng[,1], "linemedian"]
games[ ng[1:2,] ]
[1] " -3.25" "  9.98"

> ng[1:2,]
     row col
[1,] 619   3
[2,] 678   3

> str(games)
'data.frame':   720 obs. of  58 variables:
 $ Home         : chr  "Alabama" "Arizona" "Arkansas" "Arkansas St." ...
 $ Road         : chr  "USC" "BYU" "Louisiana Tech" "Toledo" ...
 $ line         : num  12 -2 24.5 4 -8.5 -3 8.5 37 -10.5 5 ...
 $ linesag      : num  12.19 0.97 24.26 -2.07 -4.78 ...
 $ linepayne    : num  12 -0.81 12.53 -0.86 -10.72 ...
deleted

 > games[ c(619,678)  , 3]
#[1] -3.25  9.98
> games[ matrix(c(619,678,3,3), ncol=2)]
[1] " -3.25" "  9.98"

所以第三列在赋值后仍然是数字,但由于我不明白矩阵索引提取的打印函数的输出看起来像是字符,而实际上它是数字。

【讨论】:

  • 我确实尝试过,但没有成功。我最初的尝试是只在带有数字的列上调用 as.numeric (除前两个之外的所有列)。无论如何,我将它添加到我的失败尝试列表中。
  • 同意。我作为猜测提供的代码......没有用。但我们都误解了games[ng] 的输出。所以我认为你的代码实际上一直在工作,当我的代码简化为:games[ ng ] &lt;- games[ , sapply(games, is.numeric)][ng[,1], "linemedian"]
  • 我验证了这一点,你是对的。在将值分配给 NA 之前,我使用“colSums(games[, c(3, 26)], na.rm = TRUE)”获取列总和。分配后,我又取了一列总和,值改变了。很容易验证算术是否已检查。感谢您的帮助。
猜你喜欢
  • 2018-01-22
  • 2012-03-25
  • 1970-01-01
  • 2019-12-12
  • 2021-09-25
  • 1970-01-01
  • 1970-01-01
  • 2021-08-25
  • 1970-01-01
相关资源
最近更新 更多