R语言 使用[不给数据框/矩阵对象指定名称]按名称删除列

mpgws1up  于 2023-06-19  发布在  其他
关注(0)|答案(3)|浏览(136)

@Joris Meys的伟大答案to this famous question建议使用名称列表按名称删除列。它需要预先为数据框/矩阵分配一个名称,并使用names(df),或用于矩阵colnames(matrix)
出于好奇,我想知道是否可以在不首先为数据框/矩阵分配名称的情况下使用类似的策略。我在回答这个问题时一直在思考这个事实(从我获取样本数据的地方)。
我建议的解决方案删除列select如下:

bind_cols(split(df$b, df$year)) %>% select(-'1997')

我第一次尝试使用do.call(cbind, split(df$b, df$year)),但这给出了一个矩阵,dplyr::select不喜欢这样。现在我当然可以 * 正面选择 *:

do.call(cbind, split(df$b, df$year))[,c('1996','1998')]

也可以使用subset

subset(do.call(cbind, split(df$b, df$year)), select = - `1997`)

我的问题是如何通过名称使用[进行“负选择”(这里:丢弃1997),而没有矩阵/ Dataframe 的先前分配,即在一个班轮。

数据

set.seed(77)
df <- data.frame(year = rep(1996:1998,3), a = runif(9), b = runif(9), e = runif(9))

# required result something like: (result from code above)   

          1996      1998
[1,] 0.4569087 0.9881951
[2,] 0.1658851 0.4475605
[3,] 0.3647157 0.7033574
j2cgzkjk

j2cgzkjk1#

显然,有很多方法可以实现这一点,但如果你只想按名称使用负子集,那么一种方法是使用你的原始数据框架来获取目标的第一个位置,然后使用它来删除它,即:

do.call(cbind, split(df$b, df$year))[,-which(df$year == '1997')[1]]

其给出,

1996      1998
[1,] 0.4569087 0.9881951
[2,] 0.1658851 0.4475605
[3,] 0.3647157 0.7033574

**注1:**您的初始 Dataframe 必须在year上排序
**注2:**可以使用cbind.data.frame将输出作为 Dataframe

kx1ctssn

kx1ctssn2#

这不会按名称选择列,但是如果您首先使用[进行负选择来过滤split中的行呢?

do.call(cbind, split(df[-which(df$year == 1997),"b"], df[-which(df$year == 1997), "year"]))
#>           1996      1998
#> [1,] 0.4569087 0.9881951
#> [2,] 0.1658851 0.4475605
#> [3,] 0.3647157 0.7033574

或者可能是一个超长的一行程序,用于负列索引

do.call(cbind, split(df$b, df$year))[,-which(colnames(do.call(cbind, split(df$b, df$year))) == "1997")]
#>           1996      1998
#> [1,] 0.4569087 0.9881951
#> [2,] 0.1658851 0.4475605
#> [3,] 0.3647157 0.7033574

不过,你可以用管子把它浓缩

do.call(cbind, split(df$b, df$year)) %>%  .[,-which(colnames(.) == "1997")]
#>           1996      1998
#> [1,] 0.4569087 0.9881951
#> [2,] 0.1658851 0.4475605
#> [3,] 0.3647157 0.7033574
mlmc2os5

mlmc2os53#

那这个呢
在一行调用匿名函数

(function(df) df[!names(df) %in% c('1997')])(as.data.frame(do.call(cbind, split(df$b, df$year))))
#       1996      1998
#1 0.2309219 0.9199970
#2 0.7308675 0.1856637
#3 0.6101509 0.6482355

as.data.frame(do.call(cbind, split(df$b, df$year)))转换为匿名函数的参数。我认为这个选项不需要赋值名称,也不依赖于先前对象的信息,因为匿名函数定义中的names(df)使用参数的名称。
但是我们可以将它声明为一个函数,并使用管道|>操作符使其更具可读性:

dropByNames <- function(df, toDrop) df[!names(df) %in% toDrop]

df |>
  with(split(b, year)) |>
  list2DF()|>
  dropByNames('1997')

相关问题