我当前的数据集如下所示:
Person Team1 Team2 Team3 Team4 Team5
1 10 11 NA NA NA
2 12 13 14 NA NA
3 15 16 NA NA NA
1 11 14 NA NA NA
如您所见,有些人(即人1)在整个数据集中重复。给定人员的重复条目可以提供关于团队从属关系的新信息,并且还可以重复旧信息。我想要做的是创建一个数据集,其中每个人只占一行,并且他们的团队成员资格的信息都包含在该行中,并且不是多余的。例如:
Person Team1 Team2 Team3 Team4 Team5
1 10 11 14 NA NA
2 12 13 14 NA NA
3 15 16 NA NA NA
因此,即使人员1在数据集中被列为团队11两次,但它只在最终版本中出现一次。仅供参考:团队变量在我的实际数据集中一直到16,而不是停在5。
答案 0 :(得分:3)
这是另一种可能性。会有优雅的方法来做到这一点。但是这会给你你所要求的结果。首先,我将数据分成Person
并为每个人创建一个向量。其次,我搜索了每个向量中的唯一元素,并使长度为length(colnames(mydf))-1
。第三,我将列表转换为数据框。最后,我为Person
添加了一列,并更改了列名称。
ana <- lapply(split(mydf, mydf$Person), function(x) c(as.matrix(x[,-1])))
bob <- lapply(lapply(ana, unique), function(y) y[1:length(colnames(mydf))-1])
cathy <- data.frame(do.call(rbind, bob))
dan <- cbind(unique(mydf$Person), cathy)
names(dan) <- names(mydf)
# Person Team1 Team2 Team3 Team4 Team5
#1 1 10 11 14 NA NA
#2 2 12 13 14 NA NA
#3 3 15 16 NA NA NA
数据强>
mydf <- structure(list(Person = c(1L, 2L, 3L, 1L), Team1 = c(10L, 12L,
15L, 11L), Team2 = c(11L, 13L, 16L, 14L), Team3 = c(NA, 14L,
NA, NA), Team4 = c(NA, NA, NA, NA), Team5 = c(NA, NA, NA, NA)), .Names = c("Person",
"Team1", "Team2", "Team3", "Team4", "Team5"), class = "data.frame", row.names = c(NA,
-4L))
答案 1 :(得分:3)
您可以尝试data.table
。通过setDT
将“data.frame”转换为“data.table”,从“wide”更改为“long”形式,通过“Person”获取“Team”列的unique
值, (unique(unlist(.SD))
),为每个“人物”创建序列列(“V2”),并通过dcast.data.table
library(data.table)
dt1 <- dcast.data.table(setDT(df)[, unique(unlist(.SD)) ,
by=Person][, V2:=paste0('Team', 1:.N), by=Person],
Person~V2, value.var='V1')
dt1
# Person Team1 Team2 Team3 Team4
#1: 1 10 11 14 NA
#2: 2 12 13 14 NA
#3: 3 15 16 NA NA
如果您需要“Team5”,“Team6”等,请创建“团队”名称的向量,使用setdiff
,然后将结果向量分配给NA
indx <- setdiff(paste0('Team', 1:5), colnames(dt1))
dt1[,(indx):=NA]
dt1
# Person Team1 Team2 Team3 Team4 Team5
#1: 1 10 11 14 NA NA
#2: 2 12 13 14 NA NA
#3: 3 15 16 NA NA NA
答案 2 :(得分:1)
我不是非常精通R,所以这段代码可能很草率,但我认为你最好的选择是创建一个包含团队成员列表的新列,例如:
data$teams = with(data, c(Team1, Team2, Team3, Team4[...]))
其他队伍的其他地方。从那里,您可以使用Person
作为键来聚合列,并执行一些不列名/唯一来消除重复:
byperson = aggregate(data, by=list(data$Person), FUN=list)
byperson$teams = sapply(sapply(byperson$teams, unlist), unique)
按人员聚合列表,将重复行(我在第一位中创建的列表)与list
函数组合在一起,后者生成列表列表。第二行然后只是通过byperson $ teams中的每个列表列表,首先在它们上面运行unlist
以将它们放入一个平面列表,然后unique
以消除欺骗。
可能有更好,更优雅的方法,可能使用melt
库,但这是你必须要做的基本想法 - 将16列重新格式化为一列列表,或者将它扩展为行,每个“成员资格”一个。后一种格式是R在我的经验中倾向于“偏好”,如下所示:
Person Team
1 10
1 11
1 14
2 12
2 13
2 14
3 15
3 16
但我不确定如何从您的数据中获取。列表列表可能是合适的,这取决于您尝试对数据执行的操作,但是在您的示例中构建的数据在R中执行任何有用的操作将非常困难。
答案 3 :(得分:1)
以下是基于cast
包中的melt
/ reshape2
函数的解决方案
library(reshape2)
# Make the data tidy
d.melt <- melt(mydf,id.vars = 'Person')
# Remove duplicates
d.uniq <- d.melt[!duplicated(d.melt[,c('Person','value')]),]
# renumber the teams
d.uniq$team <- ave(d.uniq$Person,d.uniq$Person,FUN=function(i) paste0('Team',seq_along(i)))
# cast into the desired 'wide' format
d.result <- dcast(d3,Person~team,value.var = 'value')
结果是:
# Person Team1 Team2 Team3 Team4
# 1 1 10 11 14 NA
# 2 2 12 13 14 NA
# 3 3 15 16 NA NA
如果结果必须包含一定数量的列:
all.teams <- paste0('Team',1:16)
d.result[,all.teams[!all.teams %in% colnames(d.result)]]=NA
答案 4 :(得分:0)
使用dplyr
和tidyr
包的另一种方式。
x <- read.table(text = "Person Team1 Team2 Team3 Team4 Team5
1 10 11 NA NA NA
2 12 13 14 NA NA
3 15 16 NA NA NA
1 11 14 NA NA NA", header = TRUE)
library(dplyr)
library(tidyr)
x %>%
gather(meaningless_column, Team, -Person) %>%
select(-meaningless_column) %>%
filter(!is.na(Team)) %>%
distinct %>%
arrange(Person, Team) %>%
group_by(Person) %>%
mutate(Index = paste0("Team_", seq_along(Team))) %>%
ungroup %>%
spread(Index, Team)
结果:
Person Team_1 Team_2 Team_3
1 1 10 11 14
2 2 12 13 14
3 3 15 16 NA
它会根据需要创建尽可能多的Team_n
列。