已更新:对于回复的人道歉,在我的原始示例中,我忽略了data.frame()
创建var
作为因素而不是字符向量的事实,我曾打算过。我已经纠正了这个例子,这至少会打破其中一个答案。
- 原 -
我有一个数据框,我正在执行一系列 dplyr 和 tidyr 操作,我想为要编码的指标变量添加列为0或1,并在dplyr链中执行 。因子的每个级别(当前存储为字符向量)应该在单独的列中编码,并且列名称是具有可变级别的固定前缀的串联,例如, var
的级别为 a ,新列var_a
将为1,var_a
的所有其他行将为0。
使用基数R的以下最小示例产生了我想要的结果(感谢this blog post),但我想将它全部滚动到 dplyr 链中,并且可以我不知道怎么做。
library(dplyr)
df <- data.frame(var = sample(x = letters[1:4], size = 10, replace = TRUE), stringsAsFactors = FALSE)
for(level in unique(df$var)){
df[paste("var", level, sep = "_")] <- ifelse(df$var == level, 1, 0)
}
请注意,实际数据集包含多个列,创建指示符变量时不应更改或删除任何列,但列var
除外,可以转换为类型 factor < / em>的
答案 0 :(得分:5)
它不漂亮,但这个功能应该有效
dummy <- function(data, col) {
for(c in col) {
idx <- which(names(data)==c)
v <- data[[idx]]
stopifnot(class(v)=="factor")
m <- matrix(0, nrow=nrow(data), ncol=nlevels(v))
m[cbind(seq_along(v), as.integer(v))]<-1
colnames(m) <- paste(c, levels(v), sep="_")
r <- data.frame(m)
if ( idx>1 ) {
r <- cbind(data[1:(idx-1)],r)
}
if ( idx<ncol(data) ) {
r <- cbind(r, data[(idx+1):ncol(data)])
}
data <- r
}
data
}
这是一个示例data.frame
dd <- data.frame(a=runif(30),
b=sample(letters[1:3],30,replace=T),
c=rnorm(30),
d=sample(letters[10:13],30,replace=T)
)
并指定要作为字符向量展开的列。你可以做到
dd %>% dummy("b")
或
dd %>% dummy(c("b","d"))
答案 1 :(得分:3)
函数作为dplyr管道的一部分的唯一要求是它将数据帧作为输入,并返回数据帧作为输出。因此,利用model.matrix
:
make_inds <- function(df, cols=names(df))
{
# do each variable separately to get around model.matrix dropping aliased columns
do.call(cbind, c(df, lapply(cols, function(n) {
x <- df[[n]]
mm <- model.matrix(~ x - 1)
colnames(mm) <- gsub("^x", paste(n, "_", sep=""), colnames(mm))
mm
})))
}
# insert into pipeline
data %>% ... %>% make_inds %>% ...
答案 2 :(得分:2)
虽然确实需要lapply
,但可以在不创建功能的情况下使用。如果var
是一个因素,您可以使用其级别;我们可以将其列绑定到lapply
,该var
循环遍历setNames
级别并创建值,使用tbl_df
命名,并将它们转换为df %>% bind_cols(as_data_frame(setNames(lapply(levels(df$var),
function(x){as.integer(df$var == x)}),
paste0('var2_', levels(df$var)))))
。
Source: local data frame [10 x 5]
var var_d var_c var2_c var2_d
(fctr) (dbl) (dbl) (int) (int)
1 d 1 0 0 1
2 c 0 1 1 0
3 c 0 1 1 0
4 c 0 1 1 0
5 d 1 0 0 1
6 d 1 0 0 1
7 c 0 1 1 0
8 c 0 1 1 0
9 d 1 0 0 1
10 c 0 1 1 0
返回
var
如果unique
是一个字符向量,而不是一个因素,您可以做同样的事情,但使用levels
代替df %>% bind_cols(as_data_frame(setNames(lapply(unique(df$var),
function(x){as.integer(df$var == x)}),
paste0('var2_', unique(df$var)))))
:
factor
两个注释:
df$var
可能是有意义的,因为它包含许多重复的级别。var
中提取数据,因为它存在于调用环境中,而不是在更大的链中存在,并且假设var
在传递的任何内容中都保持不变。除了dplyr
正常的NSE之外,引用factor
的动态值是一种痛苦,就像我所见。使用reshape2::dcast
的另一个更简单且library(reshape2)
df %>% cbind(1 * !is.na(dcast(df, seq_along(var) ~ var, value.var = 'var')[,-1]))
- 不可知的替代方案:
df
它仍然从调用环境中提取cbind
的版本,因此链条实际上只能确定您要加入的内容。因为它使用的是bind_cols
而不是data.frame
,所以结果也是tbl_df
,而不是tbl_df
,所以如果你想保留所有cbind
(如果数据很大,则智能化,您需要将bind_cols(as_data_frame( ... ))
替换为bind_cols
; factor
似乎不想为您进行转换。
但请注意,虽然此版本更简单,但在Unit: microseconds
expr min lq mean median uq max neval
factor 358.889 384.0010 479.5746 427.9685 501.580 3995.951 100
unique 547.249 585.4205 696.4709 633.4215 696.402 4528.099 100
dcast 2265.517 2490.5955 2721.1118 2628.0730 2824.949 3928.796 100
数据上相对较慢:
Unit: microseconds
expr min lq mean median uq max neval
unique 307.190 336.422 414.1031 362.6485 419.3625 3693.340 100
dcast 2117.807 2249.077 2517.0417 2402.4285 2615.7290 3793.178 100
和字符串数据:
import java.util.Scanner;
public class NestedTree
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
System.out.println("Enter the size of the tree you would like");
int size = scan.nextInt(); // Get the size of the tree
for (int i = 0; i < size; i++) {
int spaces = size - i;
for (int s = 0; s < spaces; s++) { // Print spaces
System.out.print(" ");
}
for (int r = 0; r <= i; r++) { // Print stars
System.out.print("* ");
}
System.out.print("\n"); // new line
}
}
}
对于小数据而言无关紧要,但对于更大的数据,可能值得采用并发症。
答案 3 :(得分:0)
我之所以参加此问答,是因为我真的想将model.matrix
放在magrittr管道工作流程中,或者只用tidyverse函数(对不起,baseRs)产生等效的输出。
后来,我登陆this solution,它优雅地使用了我想可能的功能(但我不是一个人想):
df <- data_frame(var = sample(x = letters[1:4], size = 10, replace = TRUE))
df %>%
mutate(unique_row_id = 1:n()) %>% #The rows need to be unique for `spread` to work.
mutate(dummy = 1) %>%
spread(var, dummy, fill = 0)
因此,我要添加链接解决方案的更新/修改版本,这样首先来到这里的人们就不必继续寻找(就像我一样)。