【问题标题】:R Conditionally transform data frame from long to wide based on multiple unique variablesR基于多个唯一变量有条件地将数据帧从长转换为宽
【发布时间】:2018-10-18 01:56:01
【问题描述】:

我知道这是关于 SO 的一个非常常见的帖子,但我花了太多时间研究一种将数据框从长格式转换为宽格式的方法,并且还没有找到可以指导的帖子我经历了整个过程。我有一个数据框,其结构与下面的 reprex 相似,但有 100 多行。基本上,相同的结构每 9 行重复一次,但变量不同。但是,为了使这篇文章尽可能具有可读性,我提供了数据框的前 9 行。请注意,每个Id 都与NamePos 相关。

library("reshape2")

test <- data.frame(
Id = c("9644", "14513", "9874",
     "12363", "9673", "9538", 
     "9585", "23447", "40396"),
Pos = c("SG", "SF", "PF", "C", "PG", "SF",
           "SG", "PF", "PG"),
Name = c("John", "James", "Bob", "Sam",
         "Mark", "Andrew", "Bobby", "Elaine", "Jerry"),
Score = c(55.66, 43.82, 37.35, 40.59,
        35.15, 27.45, 28.82, 28.95,
        34.98),
Sal = c(60000, 60000, 60000, 60000,
         60000, 60000, 60000, 60000,
         60000),
Total = c(332.77, 332.77, 332.77, 332.77,
        332.77, 332.77, 332.77, 332.77,
        332.77),
TmNumber = c(1, 1, 1, 1, 1, 1, 1, 1, 1))

我想将我的列和变量转换成这种格式:

desiredDF <- data.frame(
  TmNum = "1",
  Id1 = "9644", Id2 = "14513", Id3 = "9874", Id4 = "12363",
  Id5 = "9673", Id6 = "9538", Id7 = "9585", Id8 = "23447",
  Id9 = "403396",
  PG = "Mark", PG = "Jerry", SG = "John", SG = "Bobby",
  SF = "James", SF = "Andrew", PF = "Bob", PF = "Elaine",
  C = "Sam",
  Score1 = "55.66", Score2 = "43.82", Score3 = "3735", Score4 = "40.59",
  Score5 = "35.15", Score6 = "27.45", Score7 = "28.82", Score8 = "28.95",
  Score9 = "34.98",
  Sal = "60000",
  Total = "332.77"
)

我已经尝试了以下代码(以及几次失败的尝试):

test2 <- dcast(test, TmNum ~ Pos, value.var = "Name")
> test2
TmNum C PF PG SF SG
1     1 1  2  2  2  2

谢谢!

【问题讨论】:

  • 如果你想要一行数据框,试试data.frame(t(unlist(test)))
  • @RonakShah 我正在更新我的问题,以反映我的数据框包含多行数据(格式相似)并且我提供的代表是整个数据框的 sn-p 的事实1000 行长。这就是为什么我正在研究从长到宽的铸造。很抱歉造成混乱。
  • @Ferroao 我添加了一个更好的示例,说明我想要的数据框应该是什么样子。
  • @Ferroao 你说得对,每个Id 都与Name 相关。我尝试了您提出的解决方案,但是,它导致我的数据框基本上折叠成一行。听到可能没有解决方案有点令人失望。我会继续环顾四周,也许我可以重塑我的 df 以使其能够转变。

标签: r dataframe reshape2 dcast


【解决方案1】:

尝试合并几个 dcast:

library(reshape2)

Ave <- function(lab, x, g, FUN = seq_along) paste0(lab, ave(format(x), g, FUN = FUN))

L <- list(
  dcast(data = transform(test, ID = Ave("Id", Id, TmNumber)),
    TmNumber ~ ID, value.var = "Id"),
  dcast(data = transform(test, Pos = Ave("", Pos, TmNumber, make.unique)),
    TmNumber ~ Pos, value.var = "Name"),
  dcast(data = transform(test, SCORE = Ave("Score", Score, TmNumber)),
    TmNumber + Sal + Total ~ SCORE, value.var = "Score"))

Reduce(function(x, y) merge(x, y, by = 1), L)

给予:

  TmNumber  Id1   Id2  Id3   Id4  Id5  Id6  Id7   Id8   Id9  C   PF   PF.1   PG
1        1 9644 14513 9874 12363 9673 9538 9585 23447 40396 Sam Bob Elaine Mark
   PG.1    SF   SF.1   SG  SG.1   Sal  Total Score1 Score2 Score3 Score4 Score5
1 Jerry James Andrew John Bobby 60000 332.77  55.66  43.82  37.35  40.59  35.15
  Score6 Score7 Score8 Score9
1  27.45  28.82  28.95  34.98

【讨论】:

  • 这看起来很有希望,我今天晚些时候会试一试。我认为对原始 df 加上您的解决方案的排序将产生我想要的输出。
  • 这非常接近于我所需要的工作方式,只是 Id 列用 Id1Id2Id3 等填充,而不是保留原始值 (即964414513)。现在玩弄代码,看看我能不能弄明白。
  • 第一个 value.var 应该是“Id”,而不是“ID”。已修复。
  • 太棒了!正是我想要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多