0

我想编写一个非常简单的程序:它应该遍历数据框中的所有列,如果至少有一个大于 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

你知道如何在没有循环的情况下完成吗?

4

3 回答 3

1
ab1k <- sapply(df, function(x) any(x > 1000))
df[ab1k] <- df[ab1k]/1000
names(df)[ab1k] <- paste(names(df)[ab1k], "(in 000')")
于 2021-04-06T13:34:58.070 回答
1

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

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

但是使用 *apply 系列函数,您必须返回并在另一个步骤中更改名称 --- 我通常更喜欢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)"
  ))
于 2021-04-06T13:38:23.747 回答
0

你可以试试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)
于 2021-04-06T15:05:57.707 回答