如何在 R 中的 for 循环中使用 ifelse

How to use ifelse inside the for loop in R

我必须检查 data.frame 中所有变量的名称,如果找到匹配,需要用中位数替换该变量中的 NA 值,否则用平均值替换 NA。

data.frame cyl_spec 有 11 个变量,我必须如下替换 NA:

  1. 粘性:用中位数估算
  2. Wax:用中位数估算
  3. 其他:用均值估算

我当然可以通过一次选择一个变量来做到这一点,但我正在尝试以下代码:

attach(cyl_spec)
var <- colnames(cyl_spec)
for(val in var)
{
  if(val == 'viscosity'){viscosity[is.na(viscosity == T)] <- median(viscosity, na.rm = T)}
  else if(val == 'wax'){wax[is.na(wax == T)] <- median(wax, na.rm = T)}
  else {val[is.na(val == T)] <- mean(val, na.rm = T)}
}
detach(cyl_spec)

不知何故代码没有做任何事情,我仍然在使用此命令的变量中获得相同的 NA 编号:

sum(is.na(cyl_spec$viscosity) 

此外,当我 运行 此代码时,我收到以下警告消息:

Warning messages:
1: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA
2: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA
3: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA
4: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA
5: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA
6: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA
7: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA
8: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA
9: In mean.default(val, na.rm = T) :
  argument is not numeric or logical: returning NA

有人可以帮我找到解决方案吗,我卡住了!提前致谢!!

您不需要循环来执行此操作。此外,测试 na 值的正确语法是 is.na(var),而不是 is.na(var == TRUE)。最后,如果你想避免输入数据框的名称,你需要使用一些函数来完成它(比如 withdplyr 函数)。在这里,R 正在寻找一个名为 viscosity 的对象,该对象无处可寻,因为它是 cyl_spec 中的列的名称(其他变量名称也是如此)。

cyl_spec$viscosity[is.na(cyl_spec$viscosity)] <- median(cyl_spec$viscosity, na.rm = T)
cyl_spec$wax[is.na(cyl_spec$wax)] <- median(cyl_spec$wax, na.rm = T)
cyl_spec$val[is.na(cyl_spec$val)] <- mean(cyl_spec$val, na.rm = T)

如果您只需要处理这个 data.frame 和这三个变量,我强烈建议您坚持使用这个 base-r 解决方案。但是,如果您希望在具有更多变量的数据框上执行此操作并且希望将其自动化,则可以查看 dplyr::mutate_each。这是一个模拟数据的例子。

我们创建了一个包含 7 个变量的 data.frame 并分配了一些 NA 值。

library(dplyr)

set.seed(10)
df <- data.frame(n=runif(100),
                 m=runif(100),
                 d=runif(100),
                 o=runif(100),
                 e=runif(100),
                 f=runif(100),
                 g=runif(100))

df <- mutate_each(df,funs(ifelse(.>.8,NA,.)))

head(df)

           n          m         d           o         e          f         g
1 0.50747820 0.34434350 0.2230884 0.347860110        NA         NA        NA
2 0.30676851 0.06132255 0.5358950 0.007992606 0.6855115         NA 0.7478783
3 0.42690767 0.36897981 0.6625291 0.401344915 0.6296311         NA 0.7225419
4 0.69310208 0.40759356        NA 0.588350693 0.7508252 0.29063776 0.5457709
5 0.08513597         NA 0.1491831          NA        NA 0.07203601 0.2641231
6 0.22543662         NA 0.6700994 0.708542599 0.3600703 0.55888842 0.3057243

现在,我们对每个变量应用一个函数,从均值或中位数推断 NA 值:

df <- df %>%
## Which variables are to be recoded with mean? here, n and m
  mutate_each(funs(ifelse(is.na(.),mean(.,na.rm = TRUE),.)),n,m) %>% 
## Which variables are to be recoded with median? here, d,o,e,f,g
  mutate_each(funs(ifelse(is.na(.),median(.,na.rm = TRUE),.)),d,o,e,f,g)

head(df)

           n          m         d           o         e          f         g
1 0.50747820 0.34434350 0.2230884 0.347860110 0.3602354 0.39956699 0.4499041
2 0.30676851 0.06132255 0.5358950 0.007992606 0.6855115 0.39956699 0.7478783
3 0.42690767 0.36897981 0.6625291 0.401344915 0.6296311 0.39956699 0.7225419
4 0.69310208 0.40759356 0.4407363 0.588350693 0.7508252 0.29063776 0.5457709
5 0.08513597 0.40892568 0.1491831 0.378731867 0.3602354 0.07203601 0.2641231
6 0.22543662 0.40892568 0.6700994 0.708542599 0.3600703 0.55888842 0.3057243

尽管@scoa 已经回答了,如果您仍然想使用 for 循环来执行此操作,只需删除 attachdetach 函数,然后执行以下操作:

var <- names(cyl_spec)           #get column names
cols <- c('viscosity', 'wax')    #get the required columns
for(val in var) 
{ 
  #loop over the required columns.
  # Where it equals our required, use median, and mean elsewhere
  for(i in 1:length(cols))
    {
      if(is.element(cols[i], val))
        { 
           #get out rows with na values
           na_rows <- is.na(cyl_spec[, val])
           cyl_spec[na_rows,val] <- median(cyl_spec[,val], na.rm = T)
         }
      else
        {
          #get out rows with na values
          na_rows <- is.na(cyl_spec[, val])
          cyl_spec[na_rows,val] <- mean(cyl_spec[,val], na.rm = T)
        }
    }
}

...尽管如您所见,它非常麻烦。强烈建议您在@scoa 提供的问题和答案中直接输入它们,或者当您有(方式)超过 2 列要更改时。 (也可以考虑在 dplyr 包中使用 mutate 函数)。