【问题标题】:r data frame- convert values to text and rank from most to least occurrences per rowr 数据框 - 将值转换为文本并按每行出现次数最多到最少的顺序排列
【发布时间】:2026-02-13 14:10:01
【问题描述】:

R 新手,将公式从 excel 转换为 R 时遇到问题。任何建议都会很棒。 我有一个名为 allwins_df 的数据框,我想将其中的每个值更改为列名的第一个字母。

然后我需要计算每个字母在每个日期的出现次数,并将它们从最高到最低的出现次数排列。最后,如果出现平局,则平局获胜者是基础数字最大的字母。即在 2001 年 1 月 5 日,其中一个 B 值的值高于 A 的值,因此 B 首先是 A,然后是 C。数据帧示例:

Date        A.B  A.C  B.A   B.C  C.A  C.B…
2001-01-01  N/A  NA   0.14  0.35 0.43 NA
2001-01-02  0.8  NA   NA    0.5  NA   0.32
2001-01-03  0.75 0.8  NA    0.65 NA   0.9
2001-01-04  NA   0.66 0.91  NA   NA   NA
2001-01-05  0.52 0.62 0.48  0.82 0.4  NA

在一些帮助下,我使用以下代码将值转换为字母,但不确定是否可以使用结果输出从出现次数最多到最少进行排名并处理平局。

 cols <- sub("\\..*", "",names(allwins_df)[-1])
    mat <- which(!is.na(allwins_df[-1]), arr.ind = TRUE)
    allwins_df[-1][mat]<- allwins_df[-1][mat] <- cols[mat[, 2]]

上述代码的输出 - 仅将值更改为字母:

Date        A.B A.C B.A B.C C.A C.B…
2001-01-01  N/A NA  B   B   C   NA
2001-01-02  A   A   NA  B   NA  C
2001-01-03  A   A   NA  B   NA  C
2001-01-04  NA  A   B   NA  NA  NA
2001-01-05  A   A   B   B   C   NA

最终目标输出示例:

Date            
2001-01-01  B   C   
2001-01-02  A   B   C
2001-01-03  A   C   B
2001-01-04  B   A   
2001-01-05  B   A   C

提前致谢。

【问题讨论】:

  • 在 2001-01-04 是否缺少 A?
  • 2001-01-03 应该是“A C B”吗? B 和 C 都为 1,但 C 的值更高。
  • 你是对的。已更新

标签: r dataframe ranking


【解决方案1】:

这是tidyversetidyrdplyr 的可能策略

使用数据

dd<-read.table(text="Date        A.B  A.C  B.A   B.C  C.A  C.B
2001-01-01  N/A  NA   0.14  0.35 0.43 NA
2001-01-02  0.8  NA   NA    0.5  NA   0.32
2001-01-03  0.75 0.8  NA    0.65 NA   0.9
2001-01-04  NA   0.66 0.91  NA   NA   NA
2001-01-05  0.52 0.62 0.48  0.82 0.4  NA", header=TRUE, na.strings=c("NA","N/A"))

我们可以做到以下几点

library(tidyr)
library(dplyr)
dd %>% 
  pivot_longer(-Date) %>% 
  separate(name, c("first","second")) %>% 
  group_by(Date, first) %>% 
  filter(!is.na(value)) %>% 
  summarize(count=n(), max=max(value)) %>% 
  arrange(Date, desc(count), desc(max)) %>% 
  mutate(rank=row_number()) %>% 
  pivot_wider(Date, names_from=rank, values_from=first, values_fill=NA)

返回

  Date       `1`   `2`   `3`  
  <chr>      <chr> <chr> <chr>
1 2001-01-01 B     C     NA   
2 2001-01-02 A     B     C    
3 2001-01-03 A     C     B    
4 2001-01-04 B     A     NA   
5 2001-01-05 B     A     C   

这个想法是您将数据重塑为更整洁的格式。在这里,我们将这些列转换为行。然后把名字分开,这样我们就可以只看第一个字母了。然后我们计算它们并跟踪每个更好的最大值。我们对它们进行分类,然后将它们重塑为与您所需形状相匹配的宽格式。尽管您可能需要重新考虑这一点,因为在 R 中使用这种形状并不总是那么容易。“整洁”的数据通常是“矩形”的,其中每一行都有相同的列数。拥有像这样参差不齐的数据并不漂亮,但这完全取决于您要在下游做什么。

请注意,一般而言,在尝试将代码从 excel 直接转换为 R 时,您要小心。这两个程序的工作方式非常不同,有时解决相同的问题会涉及非常不同的策略,以便在不同的环境中高效。

【讨论】:

  • MrFlick-感谢您的帮助和洞察力。我不确定数据应该是宽的还是长的。下一步(来自我的 excel 电子表格)是将一系列 if than 语句应用于最终结果中的 x 个(最多 10 个)字母。在 excel 中,我编写了一个包含 10 多个 if 语句的决策树。我不知道如何在 R 中对它们进行编码。我不想将它们相互嵌套,我正在考虑编写小函数并将它们与 ifelse 或 ??? 一起使用。感谢您对此的任何其他想法。
  • MrFlick-您的建议几乎完美。除了代码删除所有变量都是 NA 的任何日期。但我需要所有的日期。如果一个日期只有 NA,我需要将前一个日期的值复制到这个日期。我尝试将 .drop= False 添加到 group_by,但这没有用。然后我尝试在 group_by 之后添加 mutate_all(funs(na.locf(., na.rm = FALSE))) ,但是我得到了不正确的值。任何想法或帮助都会很棒。
  • @Doug 您可能可以取出删除所有 NA 值的过滤器,但是您需要调整 summarise() 函数以正确考虑 NA 值,无论哪种方式都会给您你需要什么。
【解决方案2】:

MrFlick 解决了我的问题。我将日期向量与 Mrflick 的输出合并,得到了我正在寻找的东西。现在下个问题

【讨论】: