【问题标题】:Convert a data frame of numerics to string equivalents based on a reference range [duplicate]根据参考范围将数字数据帧转换为字符串等价物[重复]
【发布时间】:2017-08-23 20:29:22
【问题描述】:

我有一个数据框,其中包含与组 (y) 相关的数字分数,这些分数是跨不同因素 (x) 测量的,并带有结果分数。类似于下表。

BU      AUDIT CORC   GOV    PPS   TMSC   TRAIN
Unit1   2.00  0.00   2.00   4.00  1.50   2.50
Unit2   3.00  1.40   3.20   1.00  1.50   3.00
Unit3   2.50  2.40   2.80   3.00  2.75   2.50
Unit4   3.00  3.20   1.60   4.00  1.00   3.00
Unit5   2.00  2.80   2.00   2.00  3.00   2.50

表是这样创建的

df %>%
  group_by(BU, CC) %>% #BU = 'unit', CC = 'Control_Category
  summarise(avg = mean(Score, na.rm = TRUE)) %>%
  dcast(BU ~ CC, value.var = "avg") %>% print()

这些数字分数引用了一个字符串值,如下面的“表格”所示。

Control_Score >  3.499 ~ "Ineffective",
Control_Score >  2.499  & Control_Score <= 3.499 ~ "Marginally Effective",
Control_Score >= 1.500  & Control_Score <= 2.499 ~ "Generally Effective",
Control_Score >  0.000  & Control_Score <= 1.499 ~ "Highly Effective"

我尝试了一些应用函数来尝试对值进行比较。还尝试使用 case_when 变异为不可用。

最后,如果表格看起来像这样,那将是理想的:

BU, AUDIT, CORC, GOV, PPS, TMSC, TRAIN
Unit1, Generally Effective,  Highly Effective, etc, etc
Unit2, Marginally Effective, Highly Effective, etc, etc
Unit3, ...,...,...
Unit4, ...,...,...
Unit5, ...,...,...

【问题讨论】:

  • 0 不应该是高效的吗?第一行的第二列!
  • 我在这里展示的表格只是示例,不一定对应 1:1。
  • 好的。但如果他们这样做会更好。 How to make a great reproducible example in R? 这是一个很好的阅读主题。

标签: r string dplyr


【解决方案1】:

您可以使用 dplyr 中的 case_when 来执行此操作。

df1 <- read.table(header = TRUE,
  text = 'BU AUDIT CORC GOV PPS TMSC TRAIN
  Unit1   2.0  0.0 2.0   4 1.50   2.5
  Unit2   3.0  1.4 3.2   1 1.50   3.0
  Unit3   2.5  2.4 2.8   3 2.75   2.5
  Unit4   3.0  3.2 1.6   4 1.00   3.0
  Unit5   2.0  2.8 2.0   2 3.00   2.5
  ')

我把 case_when 放在一个函数中。

score_label <- function(score){
  lbl <- case_when(
    score < 1.5 ~ "Highly Effective",
    score >= 1.5 & score < 2.5 ~ "Generally Effective",
    score >= 2.5 & score < 3.5 ~ "Marginally Effective",
    score >= 3.5 ~ "Ineffective"
  )
  return(lbl)
} 

然后使用 apply 将函数应用于数据框(根据 AOSmith 的评论进行编辑,使用 dplyr 中的 mutate_at 而不是“apply”函数。更易于阅读和遵循。)

df_out <- df1 %>% 
    mutate_at(c("AUDIT", "CORC", "GOV", "PPS", "TMSC", "TRAIN"), score_label)

df_Out[,1:4]


   BU                AUDIT                 CORC                  GOV
Unit1  Generally Effective     Highly Effective  Generally Effective
Unit2 Marginally Effective     Highly Effective Marginally Effective
Unit3 Marginally Effective  Generally Effective Marginally Effective
Unit4 Marginally Effective Marginally Effective  Generally Effective
Unit5  Generally Effective Marginally Effective  Generally Effective

【讨论】:

  • 如果使用case_when,为什么不使用mutate_at
  • 是的,我刚刚尝试过,效果很好,但更具可读性。
  • mutate_at 是如何工作的?
  • Zach - 我编辑为使用 mutate_at。干净多了。
  • love mutate_at -- 我完全在我的代码中实现了它!非常感谢!
【解决方案2】:

cut 是一个很好的函数,可以将数字划分为区间并给它们起解释性的名称。

Control_Score <- c(-1, 0, 1.4, 1.5, 2.499, 2.5, 3.499, 3.5, 4)

cut(
  Control_Score,
  breaks = c(0, 1.5, 2.5, 3.5, Inf),
  labels = c(
    "Highly Effective",
    "Generally Effective",
    "Marginally Effective",
    "Ineffective"
  ),
  include.lowest = TRUE
)
# [1] <NA>                 Highly Effective     Highly Effective    
# [4] Highly Effective     Generally Effective  Generally Effective 
# [7] Marginally Effective Marginally Effective Ineffective         
# 4 Levels: Highly Effective Generally Effective ... Ineffective

正如您在-1 中看到的那样,指定间隔之外的任何值都分配给NA。因此,无效数据不太可能被忽视。

替换df中的值:

df <- read.table(
  header = TRUE,
  text = 'BU AUDIT CORC GOV PPS TMSC TRAIN
Unit1   2.0  0.0 2.0   4 1.50   2.5
Unit2   3.0  1.4 3.2   1 1.50   3.0
Unit3   2.5  2.4 2.8   3 2.75   2.5
Unit4   3.0  3.2 1.6   4 1.00   3.0
Unit5   2.0  2.8 2.0   2 3.00   2.5
  ')

df[-1] <- lapply(
  df[-1],
  cut,
  breaks = c(0, 1.5, 2.5, 3.5, Inf),
  labels = c(
    "Highly Effective",
    "Generally Effective",
    "Marginally Effective",
    "Ineffective"
  ),
  include.lowest = TRUE
)

df[-1] 仅表示“除了df 的第一列之外的所有内容”。使用实际数据所需的任何子集。

【讨论】:

  • 这看起来很合理。那么如何将该逻辑应用于现有的数字数据帧以生成与数字相反的具有字符串的相同数据帧?
【解决方案3】:

你也可以使用findInterval(),这也是一个base R函数:

myintervals <- c(-Inf, 0, 1.5, 2.5, 3.5, Inf)
mylabels    <- c(NA, "Highly Effective", "Generally Effective", 
                 "Marginally Effective", "Ineffective")

df[,-1] <- mylabels[sapply(df[,-1], function(x) findInterval(x,myintervals))]

df
##      BU               AUDIT                CORC                 GOV
## 1 Unit1 Generally Effective    Highly Effective Generally Effective
## 2 Unit2 Marginally Effectiv    Highly Effective Marginally Effectiv
## 3 Unit3 Marginally Effectiv Generally Effective Marginally Effectiv
## 4 Unit4 Marginally Effectiv Marginally Effectiv Generally Effective
## 5 Unit5 Generally Effective Marginally Effective Generally Effective
##                   PPS                TMSC               TRAIN
## 1         Ineffective Generally Effective Marginally Effectiv
## 2    Highly Effective Generally Effective Marginally Effectiv
## 3 Marginally Effectiv Marginally Effectiv Marginally Effectiv
## 4         Ineffective    Highly Effective Marginally Effectiv
## 5 Generally Effective Marginally Effective Marginally Effective

数据:

 df <- structure(list(BU = structure(1:5, .Label = c("Unit1", "Unit2",                   
     "Unit3", "Unit4", "Unit5"), class = "factor"), AUDIT = c(2, 3,                      
     2.5, 3, 2), CORC = c(0, 1.4, 2.4, 3.2, 2.8), GOV = c(2, 3.2,                        
     2.8, 1.6, 2), PPS = c(4, 1, 3, 4, 2), TMSC = c(1.5, 1.5, 2.75,                      
     1, 3), TRAIN = c(2.5, 3, 2.5, 3, 2.5)), .Names = c("BU", "AUDIT",                   
     "CORC", "GOV", "PPS", "TMSC", "TRAIN"), row.names = c(NA, 5L), class = "data.frame")

注意:我更喜欢findInterval(),因为如果您的数据超出定义的边界,它会给您一个错误,因此您会了解它们而不是将它们归类为NA 默认情况下(cut 的作用)。

【讨论】:

  • 这些间隔与我在问题中提出的间隔如何对应? c(-Inf, 0, 1.5, 2.5, 3.5, Inf)
【解决方案4】:

您可以使用ifelse 将数值更改为字符串。

BU <- c("Unit1", "Unit2", "Unit3", "Unit4", "Unit5")
Audit <- c(2,3,2.5,3,2)
CORC <- c(0,1.4,2.4,3.2,2.8)
GOV <- c(2,3.2,2.8,1.6,2)

df <- data.frame(BU, Audit, CORC, GOV)
df$BU <- as.character(df$BU)
df$Audit <- as.numeric(as.character(df$Audit))
df$CORC <- as.numeric(as.character(df$CORC))
df$GOV <- as.numeric(as.character(df$GOV))

df[,-1] <- ifelse(df[,-1]>3.499, "Ineffective",
                  ifelse(df[,-1]>2.499 & df[,-1]<=3.499, "Marginally Effective",
                         ifelse(df[,-1]>1.5 & df[,-1]<=2.499, "Generally Effective",
                                "Highly Effective")))

> df
     BU                Audit                 CORC                  GOV
1 Unit1  Generally Effective     Highly Effective  Generally Effective
2 Unit2 Marginally Effective     Highly Effective Marginally Effective
3 Unit3 Marginally Effective  Generally Effective Marginally Effective
4 Unit4 Marginally Effective Marginally Effective  Generally Effective
5 Unit5  Generally Effective Marginally Effective  Generally Effective

如果要折叠整个表格,可以添加以下代码:

df[2:(NROW(df)+1),] <- df[1:NROW(df),]
df[1,] <- colnames(df)

new_df <- apply( df, 1 , paste , collapse = "," )

输出:

> new_df
                                                                    1 
                                                  "BU,Audit,CORC,GOV" 
                                                                    2 
     "Unit1,Generally Effective,Highly Effective,Generally Effective" 
                                                                    3 
   "Unit2,Marginally Effective,Highly Effective,Marginally Effective" 
                                                                    4 
"Unit3,Marginally Effective,Generally Effective,Marginally Effective" 
                                                                    5 
"Unit4,Marginally Effective,Marginally Effective,Generally Effective" 
                                                                    6 
 "Unit5,Generally Effective,Marginally Effective,Generally Effective" 

【讨论】:

    猜你喜欢
    • 2015-09-22
    • 2022-11-04
    • 2017-07-14
    • 1970-01-01
    • 2023-01-21
    • 2014-06-07
    • 2020-07-29
    • 1970-01-01
    相关资源
    最近更新 更多