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钠
Atidyr
带有chop()
和unnest\u wide()
的解决方案
谢谢你的帮助,这很有效。我对这些列的一个担忧是,在我的实际数据集中,药物的数量和名称不断变化,因此声明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)
df %>%
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
df <- structure(list(Name = c("Name1", "Name1", "Name1", "Name2", "Name2"
), MedName = c("atenolol 25mg", "aspirin 81mg", "sildenafil 100mg",
"atenolol 50mg", "enalapril 20mg")), class = "data.frame", row.names = c(NA, -5L))