R 如何为每行返回一系列列中的第一个非空值?第二个非空值呢?
我有以下组织数据:R 如何为每行返回一系列列中的第一个非空值?第二个非空值呢?,r,hierarchy,hierarchical-data,R,Hierarchy,Hierarchical Data,我有以下组织数据: EmployeeID <- c(10:15) Job.Title <- c("Program Manager", "Development Manager", "Developer" , "Developer", "Developer", "Summer Intern") Level.1 <- c(1,1,1,1,1,1) Level.2 <- c(2,2,2,2,2,2) Level.3 <- c("",10,10,10,10,10) Leve
EmployeeID <- c(10:15)
Job.Title <- c("Program Manager", "Development Manager", "Developer" , "Developer", "Developer", "Summer Intern")
Level.1 <- c(1,1,1,1,1,1)
Level.2 <- c(2,2,2,2,2,2)
Level.3 <- c("",10,10,10,10,10)
Level.4 <- c("","",11,11,11,11)
Level.5 <- c("","","","","",12)
Level.6 <- c("","","","","","")
Pay.Type <- c("Salary", "Salary", "Salary", "Salary", "Salary", "Hourly")
acme = data.frame(EmployeeID, Job.Title, Level.1, Level.2, Level.3, Level.4, Level.5, Level.6, Pay.Type)
acme
EmployeeID Job.Title Level.1 Level.2 Level.3 Level.4 Level.5 Level.6 Pay.Type
1 10 Program Manager 1 2 Salary
2 11 Development Manager 1 2 10 Salary
3 12 Developer 1 2 10 11 Salary
4 13 Developer 1 2 10 11 Salary
5 14 Developer 1 2 10 11 Salary
6 15 Summer Intern 1 2 10 11 12 Hourly
我们可以使用
max.col
来实现这一点。查找“Level”列的索引(“i1”),将基于“i1”的“acme”子集转换为矩阵(!=”
),应用max.col
,并获取最后一个真值的列索引,减去1得到第二个最后一个真值(“i3”),使用行/列索引提取元素并创建“主管”和“经理”列
i1 <- grep("Level\\.\\d+", names(acme))
i2 <- max.col(acme[i1]!="", "last")
i3 <- i2-1
acme$Supervisor <- acme[i1][cbind(1:nrow(acme), i2)]
acme$Manager <- acme[i1][cbind(1:nrow(acme), i3)]
acme
# EmployeeID Job.Title Level.1 Level.2 Level.3 Level.4 Level.5 Level.6 Pay.Type Supervisor Manager
#1 10 Program Manager 1 2 Salary 2 1
#2 11 Development Manager 1 2 10 Salary 10 2
#3 12 Developer 1 2 10 11 Salary 11 10
#4 13 Developer 1 2 10 11 Salary 11 10
#5 14 Developer 1 2 10 11 Salary 11 10
#6 15 Summer Intern 1 2 10 11 12 Hourly 12 11
i1我们可以使用apply
行方式获得所有不为空的索引,并选择第一个和第二个值分别获得两列
acme[, c("Supervisor", "Manager")] <- t(apply(acme[, 8:3], 1,
function(x) c(x[which(x != "")[1]], x[which(x != "")[2]])))
acme
# EmployeeID Job.Title Level.1 Level.2 Level.3 Level.4 Level.5 Level.6 Pay.Type Supervisor Manager
#1 10 Program Manager 1 2 Salary 2 1
#2 11 Development Manager 1 2 10 Salary 10 2
#3 12 Developer 1 2 10 11 Salary 11 10
#4 13 Developer 1 2 10 11 Salary 11 10
#5 14 Developer 1 2 10 11 Salary 11 10
#6 15 Summer Intern 1 2 10 11 12 Hourly 12 11
应该有用
如果我们只需要主管
,我们可以忽略第二部分
acme[, "Supervisor"] <- t(apply(acme[, maxcol:mincol], 1,
function(x) x[which(x != "")[1]]))
acme[,“Supervisor”]这里是一个数据表
“一行”:
工作原理
data.frame
被强制为data.table
它的形状从宽到长的顺序
删除级别为的所有行。
现在,数据按级别编号排序(隐式表示为级别1
,级别2
,等等)
对于每个员工,提取最后一个值(主管)和最后第二个值(经理),创建由三列组成的中间结果
最后,将中间结果连接到acme
以附加新列
印刷品
注意:melt()
将发出警告消息,指出并非所有级别列都具有相同的数据类型。这是由于在acme
data.frame的定义中将整数值与字符(“”
)混合在一起造成的。最好使用NA
而不是“
”。顺便说一句:在这种情况下,通过使用na.rm=FALSE
和melt()
注意:步骤4中的简单物理排序最多适用于9个级别(Level.1
到Level.9
)。如果有更多级别,则必须提取级别编号并强制为整数。一种解决方案,使用dplyr
和tidyr
依赖于数据的重塑
library(tidyverse)
acme %>%
gather('level', 'value', starts_with('Level.')) %>%
group_by(EmployeeID) %>%
filter(value != '') %>%
summarise(Supervisor = last(value),
Manager = nth(value, -2)) %>%
left_join(acme)
R有NA值。使用空字符串比使用空字符串要好得多。我的数据帧要大得多,并且是更大代码集的一部分,因此,如果以后添加或删除其他列,则按顺序号引用列可能会导致错误。我应该为这项任务创建一个单独的数据框并将其合并回去,还是有办法编辑“apply(acme[,8:3]”以使用列名?我尝试了:acme[,c(“主管”,“经理”)]另外,我如何只返回主管?@Ankie我已经更新了答案。如果您还有疑问,请告诉我。
acme[, "Supervisor"] <- t(apply(acme[, maxcol:mincol], 1,
function(x) x[which(x != "")[1]]))
library(data.table)
setDT(acme)[melt(acme, measure.vars = patterns("Level.\\d"))[value != ""][
order(variable), .(Supervisor = value[.N], Manager = value[.N - 1]), by = EmployeeID],
on = "EmployeeID"][]
EmployeeID Job.Title Level.1 Level.2 Level.3 Level.4 Level.5 Level.6 Pay.Type Supervisor
#1: 10 Program Manager 1 2 Salary 2
#2: 11 Development Manager 1 2 10 Salary 10
#3: 12 Developer 1 2 10 11 Salary 11
#4: 13 Developer 1 2 10 11 Salary 11
#5: 14 Developer 1 2 10 11 Salary 11
#6: 15 Summer Intern 1 2 10 11 12 Hourly 12
Manager
#1: 1
#2: 2
#3: 10
#4: 10
#5: 10
#6: 11
library(tidyverse)
acme %>%
gather('level', 'value', starts_with('Level.')) %>%
group_by(EmployeeID) %>%
filter(value != '') %>%
summarise(Supervisor = last(value),
Manager = nth(value, -2)) %>%
left_join(acme)