原始数据框:
v1 = sample(letters[1:3], 10, replace=TRUE)
v2 = sample(letters[1:3], 10, replace=TRUE)
df = data.frame(v1,v2)
df
v1 v2 1 b c 2 a a 3 c c 4 b a 5 c c 6 c b 7 a a 8 a b 9 a c 10 a b
新数据框:
new_df = data.frame(row.names=rownames(df))
for (i in colnames(df)) {
for (x in letters[1:3]) {
#new_df[x] = as.numeric(df[i] == x)
new_df[paste0(i, "_", x)] = as.numeric(df[i] == x)
}
}
v1_a v1_b v1_c v2_a v2_b v2_c 1 0 1 0 0 0 1 2 1 0 0 1 0 0 3 0 0 1 0 0 1 4 0 1 0 1 0 0 5 0 0 1 0 0 1 6 0 0 1 0 1 0 7 1 0 0 1 0 0 8 1 0 0 0 1 0 9 1 0 0 0 0 1 10 1 0 0 0 1 0
对于小型数据集,这很好,但对于更大的数据集,它会变慢。
任何人都知道如何在不使用循环的情况下执行此操作?
答案 0 :(得分:24)
在@ AnandaMahto的搜索功能的帮助下更好,
model.matrix(~ . + 0, data=df, contrasts.arg = lapply(df, contrasts, contrasts=FALSE))
# v1a v1b v1c v2a v2b v2c
# 1 0 1 0 0 0 1
# 2 1 0 0 1 0 0
# 3 0 0 1 0 0 1
# 4 0 1 0 1 0 0
# 5 0 0 1 0 0 1
# 6 0 0 1 0 1 0
# 7 1 0 0 1 0 0
# 8 1 0 0 0 1 0
# 9 1 0 0 0 0 1
# 10 1 0 0 0 1 0
我认为这就是你要找的东西。如果不是这样的话,我很乐意删除。感谢@ G.Grothendieck(再次)model.matrix
的{{1}}!
cbind(with(df, model.matrix(~ v1 + 0)), with(df, model.matrix(~ v2 + 0)))
# v1a v1b v1c v2a v2b v2c
# 1 0 1 0 0 0 1
# 2 1 0 0 1 0 0
# 3 0 0 1 0 0 1
# 4 0 1 0 1 0 0
# 5 0 0 1 0 0 1
# 6 0 0 1 0 1 0
# 7 1 0 0 1 0 0
# 8 1 0 0 0 1 0
# 9 1 0 0 0 0 1
# 10 1 0 0 0 1 0
注意:您的输出只是:
with(df, model.matrix(~ v2 + 0))
注2:这给出matrix
。相当明显,但如果你想要一个as.data.frame(.)
,仍然可以用data.frame
包裹它。
答案 1 :(得分:8)
插入符号包中有一个功能可以满足您的需要,即dummyVars。 以下是作者文档中使用它的示例: http://topepo.github.io/caret/preprocess.html
library(earth)
data(etitanic)
dummies <- caret::dummyVars(survived ~ ., data = etitanic)
head(predict(dummies, newdata = etitanic))
pclass.1st pclass.2nd pclass.3rd sex.female sex.male age sibsp parch
1 1 0 0 1 0 29.0000 0 0
2 1 0 0 0 1 0.9167 1 2
3 1 0 0 1 0 2.0000 1 2
4 1 0 0 0 1 30.0000 1 2
5 1 0 0 1 0 25.0000 1 2
6 1 0 0 0 1 48.0000 0 0
如果您有稀疏数据并希望使用Matrix::sparse.model.matrix
答案 2 :(得分:3)
一种相当直接的方法是在每列上使用table
,将列中的值按data.frame
中的行数制表:
allLevels <- levels(factor(unlist(df)))
do.call(cbind,
lapply(df, function(x) table(sequence(nrow(df)),
factor(x, levels = allLevels))))
# a b c a b c
# 1 0 1 0 0 0 1
# 2 1 0 0 1 0 0
# 3 0 0 1 0 0 1
# 4 0 1 0 1 0 0
# 5 0 0 1 0 0 1
# 6 0 0 1 0 1 0
# 7 1 0 0 1 0 0
# 8 1 0 0 0 1 0
# 9 1 0 0 0 0 1
# 10 1 0 0 0 1 0
我在“x”上使用了factor
来确保即使在列中没有“c”值的情况下,输出中仍然会有“c”列,用零填充。
答案 3 :(得分:3)
我最近遇到了另一种方式。我注意到,当您运行FALSE
设置为contr.sum(5, contrasts = FALSE)
的任何对比函数时,它会为您提供一个热门编码。例如, 1 2 3 4 5
1 1 0 0 0 0
2 0 1 0 0 0
3 0 0 1 0 0
4 0 0 0 1 0
5 0 0 0 0 1
给出了
contr.onehot = function (n, contrasts, sparse = FALSE) {
contr.sum(n = n, contrasts = FALSE, sparse = sparse)
}
options(contrasts = c("contr.onehot", "contr.onehot"))
model.matrix(~ . - 1, data = df)
要为所有因素获得此行为,您可以创建新的对比度函数并将其设置为默认值。例如,
v1a v1b v1c v2a v2b v2c
1 0 0 1 0 0 1
2 0 1 0 1 0 0
3 0 0 1 0 1 0
4 1 0 0 0 1 0
5 0 1 0 0 1 0
6 0 1 0 0 0 1
7 1 0 0 0 1 0
8 0 1 0 0 1 0
9 0 1 0 1 0 0
10 0 0 1 0 0 1
这导致
string filePath = Path.GetDirectoryName(Application.ExecutablePath);
string fileName = "sampledata.csv";
string query = string.Empty;
//query = "SELECT * FROM " + fileName;
//query = "SELECT * FROM " + fileName + " WHERE [COLUMN 2] > 1";
query = "SELECT * FROM " + fileName + " WHERE [COLUMN 3] > 0.02";
// 32-bit
// OdbcConnection conn = new OdbcConnection("Driver=Microsoft Text Driver (*.txt, *.csv);Dbq=" + filePath + ";Extensions=csv;");
// 64-bit
OdbcConnection conn = new OdbcConnection("Driver=Microsoft Access Text Driver (*.txt, *.csv);Dbq=" + filePath + ";Extensions=csv;");
conn.Open();
OdbcCommand cmd = new OdbcCommand(query, conn);
OdbcDataAdapter adapter = new OdbcDataAdapter(cmd);
DataSet mydata = new DataSet("CSVData");
adapter.Fill(mydata);
conn.Close();
conn.Dispose();
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = mydata;
dataGridView1.DataMember = mydata.Tables[0].ToString();
答案 4 :(得分:3)
刚刚看到一个封闭的问题,并且没人提到使用dummies
包:
您可以使用基于dummy.data.frame()
构建的model.matrix()
函数重新编码变量,但语法更简单,选项更好并会返回数据帧:
> dummy.data.frame(df, sep="_")
v1_a v1_b v1_c v2_a v2_b v2_c
1 0 1 0 0 0 1
2 1 0 0 1 0 0
3 0 0 1 0 0 1
4 0 1 0 1 0 0
5 0 0 1 0 0 1
6 0 0 1 0 1 0
7 1 0 0 1 0 0
8 1 0 0 0 1 0
9 1 0 0 0 0 1
10 1 0 0 0 1 0
此功能的一些不错的方面是您可以轻松地为新名称(sep=
)指定分隔符,省略非编码变量(all=F
)并附带自己的选项dummy.classes
这允许您指定应编码哪些列类。
您也可以使用dummy()
功能将其应用于一列。
答案 5 :(得分:0)
这是一个更一般情况的解决方案,当未指定字母数量时:
convertABC <- function(x) {
hold <- rep(0,max(match(as.matrix(df),letters))) # pre-format output
codify <- function(x) { # define function for single char
output <- hold # take empty vector
output[match(x,letters)] <- 1 # place 1 according to letter pos
return(output)
}
to.return <- t(sapply(as.character(x),codify)) # apply it to whole vector
rownames(to.return) <- 1:nrow(to.return) # nice rownames
colnames(to.return) <- do.call(c,list(letters[1:max(match(as.matrix(df),letters))])) # nice columnnames
return(to.return)
}
此函数采用字符向量,并将其重新编码为二进制值。处理df
中的所有变量:
do.call(cbind,lapply(df,convertABC))
答案 6 :(得分:0)
library(correlationfunnel)
library(dplyr)
v1 = sample(letters[1:3], 10, replace=TRUE)
v2 = sample(letters[1:3], 10, replace=TRUE)
df = data.frame(v1,v2)
df
v1 v2
1 b c
2 c c
3 c a
4 c c
5 a a
6 b b
7 b c
8 b c
9 c a
10 b c
df$id= 1:nrow(df)
df %>%
select(-id) %>%
binarize()
# A tibble: 10 x 6
v1__a v1__b v1__c v2__a v2__b v2__c
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0 1 0 0 0 1
2 0 0 1 0 0 1
3 0 0 1 1 0 0
4 0 0 1 0 0 1
5 1 0 0 1 0 0
6 0 1 0 0 1 0
7 0 1 0 0 0 1
8 0 1 0 0 0 1
9 0 0 1 1 0 0
10 0 1 0 0 0 1