有条件地删除每列的值,但使用循环将每列保留为新数据框

Conditionally remove value for each column but keep each column as a new dataframe using a loop

我有以下简化的数据框。

test <- data.frame(
  ice = c(1, 0.8, 0.5, 0.4),
  eonia = c(0.5, 0, 0, -0.4),
  euribor = c(1, -0.8, 1, -0.2),
  cp = c(-0.7, -0.6, -0.4, -0.5)
)

row.names(test) <- colnames(test)

我想为每一列应用一个条件,它只保留那些满足条件的值:

test[(test$ice>= 0.8 & test$ice< 1) | (test$ice<= -0.8 & test$ice> -1), , drop=FALSE]

但是,我的真实数据框包含许多变量,我不想将此代码“手动”应用到每一列。 请注意,在针对此条件进行过滤后,我可能需要将每一列添加到列表或新数据框中。

是否有一种有效的方法来遍历每一列,并可能将每一列安全地作为新数据框或将其添加到列表中。

第一个数据框(或列表的一部分)应如下所示:

      ice
ice   1
eonia 0.8

非常感谢

我们可以定义自定义函数并循环遍历列。在这里,我使用的 dplyr::between 等同于 x >= left & x <= right 但它可以很容易地修改为您需要的代码。

custom_filter <- function(df, colName, right, left, right_n = -right, left_n = -left){
  require(dplyr)
  require(rlang)
  
df %>% 
  filter(between(!! sym(colName), right, left) | between(!! sym(colName), right_n, left_n))
}


lapply(names(test) , function(colN) custom_filter(test, colN, 0.8, 1))

使用您的选择逻辑创建一个 f函数,然后遍历数据中的每一列并使用以下函数对其进行子集化:

f <- function(x) (x >= 0.8 & x < 1) | (x <= -0.8 & x > -1)
lapply(names(test), \(n) test[ f(test[[n]]), n, drop=FALSE] )

如果函数需要接受 0 两侧的低点和高点参数,也可以在其中进行编辑:

f <- function(x, low, high) abs(x) >= low & abs(x) < high
lapply(names(test), \(n) test[ f(test[[n]], 0.8, 1.0), n, drop=FALSE] )

#[[1]]
#      ice
#eonia 0.8
#
#[[2]]
#[1] eonia
#<0 rows> (or 0-length row.names)
#
#[[3]]
#      euribor
#eonia    -0.8
#
#[[4]]
#[1] cp
#<0 rows> (or 0-length row.names)

[] 中的条件已应用于每一列。为了在丢失值的情况下保持矩阵布局,您可以显式添加例如NA.

这是一个例子(在@thelatemail 的帮助下编辑):

test[ !(( test >= 0.8 & test < 1 )|( test <= -0.8 & test > -1)) ] <- NA

        ice eonia euribor cp
ice      NA    NA      NA NA
eonia   0.8    NA    -0.8 NA
euribor  NA    NA      NA NA
cp       NA    NA      NA NA

请记住,这是所谓的就地修改,直接更改您的数据集(此处为数据框 test)。