R 转置/重塑数据帧,不带“;“时间变量”;从长格式到宽格式

R 转置/重塑数据帧,不带“;“时间变量”;从长格式到宽格式,r,reshape,transpose,r-faq,data.table,dplyr,tidyr,R,Reshape,Transpose,R Faq,Data.table,Dplyr,Tidyr,我有一个遵循以下长模式的数据帧: Name MedName Name1 atenolol 25mg Name1 aspirin 81mg Name1 sildenafil 100mg Name2 atenolol 50mg Name2 enalapril 20mg 并希望获得以下信息(我不在乎是否可以以这种方式命名列,只希望数据采用这种格式): 通过这个网站,我已经熟悉了重塑/重塑2软件包,并经历了几次尝试,试图让它发挥作用,

我有一个遵循以下长模式的数据帧:

   Name          MedName
  Name1    atenolol 25mg
  Name1     aspirin 81mg
  Name1 sildenafil 100mg
  Name2    atenolol 50mg
  Name2   enalapril 20mg
并希望获得以下信息(我不在乎是否可以以这种方式命名列,只希望数据采用这种格式):

通过这个网站,我已经熟悉了重塑/重塑2软件包,并经历了几次尝试,试图让它发挥作用,但迄今为止都失败了

当我尝试
dcast(dataframe,Name~MedName,value.var='MedName')
时,我只得到一组列,它们是药物名称的标志(被转换的值是1或0),例如:

在我融化数据集后,我还尝试了
dcast(数据集,Name~variable)
,但这只是吐出了以下内容(仅计算每个人有多少药物):

最后,我尝试熔化数据,然后使用
idvar=“Name”
timevar=“variable”
(其中所有的都是MedName),但这似乎不是为我的问题而构建的,因为如果有多个匹配的idvar,则重塑只采用第一个MedName,而忽略其余的MedName


有人知道如何使用重塑或其他R函数来实现这一点吗?我意识到可能有一种方法可以以更混乱的方式完成这项工作,使用一些for循环和条件来基本上拆分和重新粘贴数据,但我希望有一种更简单的解决方案。非常感谢你

假设您的数据位于对象
数据集中

library(plyr)
## Add a medication index
data_with_index <- ddply(dataset, .(Name), mutate, 
                         index = paste0('medication', 1:length(Name)))    
dcast(data_with_index, Name ~ index, value.var = 'MedName')

##    Name   medication1    medication2      medication3
## 1 Name1 atenolol 25mg   aspirin 81mg sildenafil 100mg
## 2 Name2 atenolol 50mg enalapril 20mg             <NA>
库(plyr)
##添加药物索引

使用_index的数据_在使用
重塑之前,您始终可以生成唯一的
timevar
。在这里,我使用
ave
应用函数
seq_along
“along”每个“Name”


test@LateMail的解决方案与此类似。当我生成时间变量时,我使用
rle
,以防我没有交互工作,并且
Name
变量需要是动态的

# start with your example data
x <- 
    data.frame(
        Name=c(rep("name1",3),rep("name2",2)),
        MedName=c("atenolol 25mg","aspirin 81mg","sildenafil 100mg",
            "atenolol 50mg","enalapril 20mg")
    )

# pick the id variable
id <- 'Name'

# sort the data.frame by that variable
x <- x[ order( x[ , id ] ) , ]

# construct a `time` variable on the fly
x$time <- unlist( lapply( rle( as.character( x[ , id ] ) )$lengths , seq_len ) )

# `reshape` uses that new `time` column by default
y <- reshape( x , idvar = id , direction = 'wide' )

# done
y
#从示例数据开始

这实际上似乎是一个相当常见的问题,因此我在“splitstackshape”包中包含了一个名为
getanID
的函数

它的作用如下:

library(splitstackshape)
getanID(test, "Name")
#     Name          MedName .id
# 1: name1    atenolol 25mg   1
# 2: name1     aspirin 81mg   2
# 3: name1 sildenafil 100mg   3
# 4: name2    atenolol 50mg   1
# 5: name2   enalapril 20mg   2
由于“data.table”与“splitstackshape”一起加载,因此您可以访问
dcast.data.table
,因此可以像@mnel的示例一样继续

dcast.data.table(getanID(test, "Name"), Name ~ .id, value.var = "MedName")
#     Name             1              2                3
# 1: name1 atenolol 25mg   aspirin 81mg sildenafil 100mg
# 2: name2 atenolol 50mg enalapril 20mg               NA

该函数基本上通过标识为创建“时间”列的组来实现一个
序列(.N)

通过该包,这可以通过新的
rowid
函数轻松解决:

library(data.table)
dcast(setDT(d1), 
      Name ~ rowid(Name, prefix = "medication"), 
      value.var = "MedName")
其中:

给出相同的结果


类似的方法,但现在使用和包:

library(dplyr)
library(tidyr)
d1 %>%
  group_by(Name) %>%
  mutate(rn = paste0("medication",row_number())) %>%
  spread(rn, MedName)
其中:


下面是一个较短的方法,利用
unlist
处理名称的方式:

library(dplyr)
df1 %>% group_by(Name) %>% do(as_tibble(t(unlist(.[2]))))
# # A tibble: 2 x 4
# # Groups:   Name [2]
#      Name      MedName1       MedName2         MedName3
#     <chr>         <chr>          <chr>            <chr>
#   1 name1 atenolol 25mg   aspirin 81mg sildenafil 100mg
#   2 name2 atenolol 50mg enalapril 20mg             <NA>
库(dplyr)
df1%%>%group_by(Name)%%>%do(作为不可修改的(t(未列出([2]))
##A tibble:2 x 4
##组:名称[2]
#姓名MedName1 MedName2 MedName3
#                                    
#1名1阿替洛尔25mg阿司匹林81mg西地那非100mg
#2名2阿替洛尔50mg依那普利20mg

一个干净的解决方案包括来自
tidyr
软件包版本
1.1.0
的非常有用的
pivot\u wide
功能。这样,您还可以使用参数
names\u glue
直接指定列名

library(tidyr)
library(dplyr)

dataframe %>% 
  group_by(Name) %>% 
  mutate(row_n = row_number()) %>% 
  pivot_wider(id_cols = Name, names_from = row_n, values_from = MedName, names_glue = "medication{row_n}")
输出

# A tibble: 2 x 4
# Groups:   Name [2]
#   Name  medication1   medication2    medication3     
#   <chr> <chr>         <chr>          <chr>           
# 1 Name1 atenolol 25mg aspirin 81mg   sildenafil 100mg
# 2 Name2 atenolol 50mg enalapril 20mg NA  
#一个tible:2 x 4
#分组:名称[2]
#名称药物1药物2药物3
#                                  
#1名1阿替洛尔25mg阿司匹林81mg西地那非100mg
#2名2阿替洛尔50mg依那普利20mg钠

A
tidyr
带有
chop()
unnest\u wide()
的解决方案

library(tidyr)
df2%>%
印章(-Name)%>%
unnest_wide(MedName,names_sep=“”)
##A tibble:2 x 4
#姓名MedName1 MedName2 MedName3
#                                  
#1名1阿替洛尔25mg阿司匹林81mg西地那非100mg
#2名2阿替洛尔50mg依那普利20mg钠

参数
names\u sep=”“
是必需的;否则,新的列名将是
.1
.2
.3

谢谢您的帮助,这很有效。我对这些列的一个担忧是,在我的实际数据集中,药物的数量和名称不断变化,因此声明MedName=c(所有名称)可能会有点过分,但我感谢您的帮助,并且可能会在其他问题上使用此方法。@Hotamd6-无需手动指定所有名称-您只需在数据集名称上执行查找和替换操作,如
gsub(“MedName.”、“Medicing”)、名称(重塑测试数据)、修复=TRUE)
以获得与上面@mnel相同的结果。我不确定是否理解您关于在“Name”变量需要动态时使用
rle
的评论。@thelatemail的解决方案不也允许这样的灵活性吗(而且不必先对数据进行排序)?@AnandaMahto也许你是对的。我想你可以使用
id这个解决方案有一个小问题。当列数超过10时,按顺序排序。例如,启动
药物1、药物10、药物11、药物12、…、药物2
。如何解决排序问题?
library(data.table)
dcast(setDT(d1), 
      Name ~ rowid(Name, prefix = "medication"), 
      value.var = "MedName")
   Name    medication1     medication2       medication3
1 Name1  atenolol 25mg    aspirin 81mg  sildenafil 100mg
2 Name2  atenolol 50mg  enalapril 20mg              <NA>
dcast(setDT(d1)[, rn := 1:.N, by = Name], 
      Name ~ paste0("medication",rn), 
      value.var = "MedName")
library(dplyr)
library(tidyr)
d1 %>%
  group_by(Name) %>%
  mutate(rn = paste0("medication",row_number())) %>%
  spread(rn, MedName)
Source: local data frame [2 x 4]
Groups: Name [2]

    Name   medication1    medication2      medication3
  (fctr)         (chr)          (chr)            (chr)
1  Name1 atenolol 25mg   aspirin 81mg sildenafil 100mg
2  Name2 atenolol 50mg enalapril 20mg               NA
library(dplyr)
df1 %>% group_by(Name) %>% do(as_tibble(t(unlist(.[2]))))
# # A tibble: 2 x 4
# # Groups:   Name [2]
#      Name      MedName1       MedName2         MedName3
#     <chr>         <chr>          <chr>            <chr>
#   1 name1 atenolol 25mg   aspirin 81mg sildenafil 100mg
#   2 name2 atenolol 50mg enalapril 20mg             <NA>
library(tidyr)
library(dplyr)

dataframe %>% 
  group_by(Name) %>% 
  mutate(row_n = row_number()) %>% 
  pivot_wider(id_cols = Name, names_from = row_n, values_from = MedName, names_glue = "medication{row_n}")
# A tibble: 2 x 4
# Groups:   Name [2]
#   Name  medication1   medication2    medication3     
#   <chr> <chr>         <chr>          <chr>           
# 1 Name1 atenolol 25mg aspirin 81mg   sildenafil 100mg
# 2 Name2 atenolol 50mg enalapril 20mg NA  
library(tidyr)

df2 %>%
  chop(-Name) %>%
  unnest_wider(MedName, names_sep = "")

# # A tibble: 2 x 4
#   Name  MedName1      MedName2       MedName3        
#   <chr> <chr>         <chr>          <chr>           
# 1 Name1 atenolol 25mg aspirin 81mg   sildenafil 100mg
# 2 Name2 atenolol 50mg enalapril 20mg NA