什么是有效的方法(欢迎包括非基础包的任何解决方案)将虚拟变量折叠回一个因子。
race
1 White
2 Asian
3 White
4 Black
5 Asian
6 Hispanic
7 White
8 White
9 White
10 Black
期望的输出:
dat <- structure(list(race.White = c(1L, 0L, 1L, 0L, 0L, 0L, 1L, 1L,
1L, 0L), race.Hispanic = c(0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L,
0L), race.Black = c(0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L),
race.Asian = c(0L, 1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("race.White",
"race.Hispanic", "race.Black", "race.Asian"), row.names = c(NA,
-10L), class = "data.frame")
数据:
apply(dat, 1, function(x) sub("[^.]+\\.", "", colnames(dat))[x])
我尝试了什么:
这是一种可行的解决方案,但我相信它有更好的索引/ dplyr / data.table / .etc解决方案。
#!/bin/sh
type apt-cyg || exit
apt-cyg install git python-{jinja2,six,yaml}
git clone --depth 1 git://github.com/ansible/ansible
cd ansible
PATH+=:~+/bin
export PYTHONPATH=~+/lib
ansible --version
答案 0 :(得分:3)
我们可以使用max.col
获取列索引,根据该列索引对列名称进行子集化,并使用sub
删除前缀。
sub('[^.]+\\.', '', names(dat)[max.col(dat)])
#[1] "White" "Asian" "White" "Black" "Asian" "Hispanic"
#[7] "White" "White" "White" "Black"
在这里,我假设每行有一个1
。如果有多个1,我们可以使用ties.method='first'
或ties.method='last'
选项。
或者另一个选项是使用列序列执行%*%
,将列名称子集化,并使用sub
删除前缀。
sub('[^.]+\\.', '', names(dat)[(as.matrix(dat) %*%seq_along(dat))[,1]])
或者我们可以使用pmax
sub('[^.]+\\.', '', names(dat)[do.call(pmax,dat*seq_along(dat)[col(dat)])])
答案 1 :(得分:3)
另一个想法:
ff = function(x)
{
ans = integer(nrow(x))
for(i in seq_along(x)) ans[as.logical(x[[i]])] = i
names(x)[ans]
}
sub("[^.]+\\.", "", ff(dat))
#[1] "White" "Asian" "White" "Black" "Asian" "Hispanic" "White" "White" "White" "Black"
与akrun的替代品进行比较:
akrun1 = function(x) names(x)[max.col(x, "first")]
akrun2 = function(x) names(x)[(as.matrix(x) %*% seq_along(x))[, 1]]
akrun3 = function(x) names(x)[do.call(pmax, x * seq_along(x)[col(x)])]
akrunlike = function(x) names(x)[do.call(pmax, Map("*", x, seq_along(x)))]
DF = setNames(as.data.frame("[<-"(matrix(0L, 1e4, 1e3),
cbind(seq_len(1e4), sample(1e3, 1e4, TRUE)),
1L)),
paste("fac", 1:1e3, sep = ""))
identical(ff(DF), akrun1(DF))
#[1] TRUE
identical(ff(DF), akrun2(DF))
#[1] TRUE
identical(ff(DF), akrun3(DF))
#[1] TRUE
identical(ff(DF), akrunlike(DF))
#[1] TRUE
microbenchmark::microbenchmark(ff(DF), akrun1(DF), akrun2(DF),
akrun3(DF), akrunlike(DF),
as.matrix(DF), col(DF), times = 30)
#Unit: milliseconds
# expr min lq median uq max neval
# ff(DF) 61.99124 64.56194 78.62267 102.18424 152.64891 30
# akrun1(DF) 296.89042 314.28641 327.95059 353.46185 394.46013 30
# akrun2(DF) 103.76105 114.01497 120.12191 129.86513 166.13266 30
# akrun3(DF) 1141.46478 1163.96842 1178.92961 1203.83848 1231.70346 30
# akrunlike(DF) 125.47542 130.20826 141.66123 157.92743 203.42331 30
# as.matrix(DF) 19.46940 20.54543 28.22377 35.69575 87.06001 30
# col(DF) 103.61454 112.75450 116.00120 126.09138 176.97435 30
我包含as.matrix()
和col()
只是为了表明&#34; list&#34; -y结构可以方便地进行高效循环。例如,与逐行循环相比,使用逐列循环的方法并不需要时间来转换数据结构。