从长到宽重塑并创建具有二进制值的列

Posted

技术标签:

【中文标题】从长到宽重塑并创建具有二进制值的列【英文标题】:Reshape from long to wide and create columns with binary value 【发布时间】:2016-06-10 08:51:06 【问题描述】:

我知道tidyr 包中的spread 函数,但这是我无法实现的。 我有一个data.frame,其中包含如下定义的 2 列。我需要将Subject 列转置为具有 1 和 0 的二进制列。

下面是数据框:

studentInfo <- data.frame(StudentID = c(1,1,1,2,3,3),
         Subject = c("Maths", "Science", "English", "Maths", "History", "History"))

> studentInfo
  StudentID Subject
1         1   Maths
2         1 Science
3         1 English
4         2   Maths
5         3 History
6         3 History

我期待的输出是:

  StudentID Maths Science English History
1         1     1       1       1       0
2         2     1       0       0       0
3         3     0       0       0       1

如何使用spread() 函数或任何其他函数来做到这一点。

【问题讨论】:

【参考方案1】:

使用reshape2,我们可以将dcast从长到宽。

由于您只想要二元结果,我们可以先unique 数据

library(reshape2)

si <- unique(studentInfo)
dcast(si, formula = StudentID ~ Subject, fun.aggregate = length)

#  StudentID English History Maths Science
#1         1       1       0     1       1
#2         2       0       0     1       0
#3         3       0       1     0       0

使用tidyrdplyr 的另一种方法是

library(tidyr)
library(dplyr)

studentInfo %>%
  mutate(yesno = 1) %>%
  distinct %>%
  spread(Subject, yesno, fill = 0)

#  StudentID English History Maths Science
#1         1       1       0     1       1
#2         2       0       0     1       0
#3         3       0       1     0       0

虽然我还不是 tidyr 语法的粉丝...

【讨论】:

【参考方案2】:

我们可以从base R使用table

+(table(studentInfo)!=0)
#            Subject
#StudentID English History Maths Science
 #       1       1       0     1       1
 #       2       0       0     1       0
 #       3       0       1     0       0

【讨论】:

哇,这是一种非常优雅的使用方式。但如果数据帧较大,它会给出类似“表错误:尝试使用 >= 2^31 个元素创建表”的消息 @sachinv 你可能已经超过了观察次数的限制。【参考方案3】:

使用 tidyr

library(tidyr)
studentInfo <- data.frame(
  StudentID = c(1,1,1,2,3,3),
  Subject = c("Maths", "Science", "English", "Maths", "History", "History"))

pivot_wider(studentInfo,
            names_from = "Subject", 
            values_from = 'Subject', 
            values_fill = 0,
            values_fn = function(x) 1)
#> # A tibble: 3 x 5
#>   StudentID Maths Science English History
#>       <dbl> <int>   <int>   <int>   <int>
#> 1         1     1       1       1       0
#> 2         2     1       0       0       0
#> 3         3     0       0       0       1

由reprex package (v0.3.0) 于 2019 年 9 月 19 日创建

【讨论】:

这个解决方案很棒...您能否详细说明一下 ~+(as.logical(length(.)))))。具体来说,你能指出我在哪里可以找到更多关于使用“+”的文档?谢谢! 感谢thisisrg,这里+ 会将逻辑转换为整数,+TRUE 为1。因此调用的结果始终为1,除非长度为零。 谢谢。 pivot_wider 创建虚拟变量实际上很复杂,但您的代码也帮助我使用 T/F 值做到这一点。我不得不将data.frame 更改为tibble,没有它就无法工作,不知道为什么。 r studentInfo &lt;- tibble(StudentID = c(1,1,1,2,3,3), Subject = c("Maths", "Science", "English", "Maths", "History", "History")) pivot_wider(studentInfo, names_from = Subject, values_from = Subject, values_fill = list(Subject = F), values_fn = list(Subject = is.character)) 嗨,James,在我的系统上,无论我使用 data.frame 还是 tibble(R 和 tidyr 的最新发布版本),您的代码都会给出相同的输出。

以上是关于从长到宽重塑并创建具有二进制值的列的主要内容,如果未能解决你的问题,请参考以下文章

tidyR 从长到宽的数据?

Mysql,重塑数据从长/高到宽

athena presto - 从长到宽的多列

在 R 中使用多个观察值从长到宽转换

使用两列值和缺失数据重塑数据集

使用熊猫将数据帧从长到宽转换-单行输出