如果最大值超过特定限制,则将列除以 1000

Divide column by 1000 if maximum exceed certain limit

我想编写一个非常简单的程序:它应该遍历数据框中的所有列,如果至少有一个观察值大于 1000,那么程序应该将该变量除以 1000,然后将 "in (000)" 添加到变量名。

我的解决方案

set.seed(42)
df <- data.frame("Norm" = rnorm(100, 1000, 0.1), rexp(100))

for (var in seq_len(ncol(df))) {
  if (max(df[, var], na.rm = T) > 1000) {
    df[, var] <- df[, var] / 1000
    colnames(df)[var] <- print(paste(colnames(df[var]), "(in 000')"))
  }
}

不过我觉得有点不方便。我认为这里不需要循环。我试着用应用来做,但我不确定为什么我得到的是除以 1000 的列的最大值,而不是每个值除以 1000 的数据框:

apply(df, 2, function(x) ifelse(max(x) > 1000, x/1000, x))

 Norm rexp.100. 
0.9999925 0.4473922

你知道如何不用循环来完成吗?

ab1k <- sapply(df, function(x) any(x > 1000))
df[ab1k] <- df[ab1k]/1000
names(df)[ab1k] <- paste(names(df)[ab1k], "(in 000')")

apply 用于矩阵,不要在数据帧上使用它。 ifelse 用于矢量测试 - 输出与输入的形状相同。您对 ifelse() 的输入是长度为 1 的 max(x) > 1000,因此结果将为长度 1。您可以使用 lapply 代替 for,使用 if(){}else{} 代替ifelse():

df[] <- lapply(df, function(x) if(max(x, na.rm = TRUE) > 1000) {x / 1000}else{x})

但是使用 *apply family functions 你必须返回并在另一个步骤中更改名称---在这种情况下我通常更喜欢 for

但我可能会这样做而不循环:

cols_over_1000 = sapply(df, max, na.rm = TRUE) > 1000
df[cols_over_1000] = df[cols_over_1000] / 1000
names(df)[cols_over_1000] = paste(names(df)[cols_over_1000], "(in '000)")

或在dplyr:

library(dplyr)
df %>%
  mutate(across(
    where(~ any(. > 1000)),
    ~ . / 1000,
    .names = "{.col} (in '000)"
  ))

您可以像这样尝试 purrr 包:

library(dplyr)
library(purrr)

my_fun <- function(x,y){
      if(max(x, na.rm = T)>1000){
            return(rename_with(tibble(x/1000),~paste0(y,"(in '000)")))
      }else{return(rename_with(tibble(x),~y))}
}

map2_dfc(df,names(df),my_fun)