【问题标题】:How to drop columns from data frame with less than 2 unique levels in R如何从R中少于2个唯一级别的数据框中删除列
【发布时间】:2015-04-20 22:49:47
【问题描述】:

我有一个数据集,其中包含约 200,000 行的数字和分类变量,但许多变量是常量(包括数字和 cat)。我正在尝试创建一个新的数据集,其中删除了 length(unique(data.frame$factor))<=1 变量。

到目前为止的示例数据集和尝试:

Temp=c(26:30)
Feels=c("cold","cold","cold","hot","hot")
Time=c("night","night","night","night","night")
Year=c(2015,2015,2015,2015,2015)
DF=data.frame(Temp,Feels,Time,Year)

我认为循环会起作用,但在我下面的 2 次尝试中有些东西不起作用。我试过了:

for (i in unique(colnames(DF))){
  Reduced_DF <- DF[,(length(unique(DF$i)))>1]
}

但我确实需要一个长度(唯一(DF$columns))>1 的列名的向量,所以我尝试了以下方法,但无济于事。

for (i in unique(DF)){
  if (length(unique(DF$i)) >1)
  {keepvars <- c(DF$i)}
  Reduced_DF <- DF[keepvars]
}

有没有人对这种类型的子集/删除少于特定级别数的列有经验?

【问题讨论】:

  • 另外,您的 for 循环不起作用的几个原因:1)您在每次迭代中创建一个新变量 Reduced_DF 而不是更改原始变量,这意味着它在每次循环后都会忘记, 2)你不能访问带有DF$i的列,你需要DF[[i]],3)表达式DF[,(length(unique(DF$i)))&gt;1]试图从所有列中提取子集,而不是决定是否保留i

标签: r


【解决方案1】:

您可以通过以下方式了解每列中有多少个唯一值:

sapply(DF, function(col) length(unique(col)))
#  Temp Feels  Time  Year 
#  5     2     1     1 

您可以使用它来对列进行子集化:

DF[, sapply(DF, function(col) length(unique(col))) > 1]
#   Temp Feels
# 1   26  cold
# 2   27  cold
# 3   28  cold
# 4   29   hot
# 5   30   hot

【讨论】:

  • 是的,如果您出于其他明确目的需要名称,例如:names(DF)[sapply(DF, function(x) length(unique(x))&gt;1 )] 就可以了。
  • 或者DF[sapply(DF, function(x) !is.factor(x) | nlevels(x) &gt; 1)],如果你想介绍nlevels - 一个因子的水平数。
  • Filter(function(x) length(unique(x)) &gt; 1, DF) 以获得更好的代码。
  • 感谢您的反馈。这些都有效,并为将来的使用提供了其他建议。我向@DavidRobinson 快速提问,我注意到虽然在使用[, sapply()] 将函数应用于所有行并在列上进行子集化时明确是有意义的,但它也可以在没有, 的情况下工作。这仅仅是因为length() 是一个列/因子函数,所以默认情况下它适用于所有行吗?再次感谢大家!
  • @surfhoya 谢谢。不完全是:这是因为您可以使用DF[, condition]DF[condition] 访问数据框的列,因为数据框是列表的一种特殊情况。例如,尝试mtcars[, 1:5],然后尝试mtcars[1:5](结果相同)。
【解决方案2】:

data.table 的另一种方式

#Convert object to data.table object
library(data.table)
setDT(DF)

#Drop columns
todrop <- names(DF)[which(sapply(DF,uniqueN)<2)]
DF[, (todrop) := NULL]

此方法的一个优点是它不会复制(当您拥有尽可能多的列时,这可能很有用)。

如果您使用data.table 1.9.4,您将更改为以下内容:

#Drop columns
todrop <- names(DF)[which(sapply(DF,function(x) length(unique(x)<2))]
DF[, (todrop) := NULL]

【讨论】:

  • 感谢@Mike.Gahan 使用data.table 的方法。我有兴趣了解有关此软件包和功能的更多信息,但在我的最后,代码出错了,因为找不到 uniqueN。我错过了什么吗?
  • 我的错...uniqueN是在data.table 1.9.5上实现的,最新的CRAN版本是1.9.4。如果你想使用这种方法,你可以下载 1.9.5 library(devtools); install_github("Rdatatable/data.table", build_vignettes = FALSE),也可以将uniqueN 替换为length(unqieu(x))
【解决方案3】:

我还有另一种可能的解决方案,用 2 行代码删除具有分类值的列,定义一个包含分类值列的列表(第一行)并用第二行删除它们。 df 是我们的数据框

带有分类列的df:

 list=pd.DataFrame(df.categorical).columns
 df= df.drop(list,axis=1)

运行代码后的df:

【讨论】:

  • 问题是关于 R 而不是 Python :) 它在标题中明确指定。
  • 你是对的,我把评论放在错误的窗口中(我以为是 Python 而不是 R)。不知道能不能删?谢谢
  • 是的,这可能取决于您的徽章/积分,但我认为应该可以删除您的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-06
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
  • 2013-06-09
相关资源
最近更新 更多