我想将data.table cols的子集转换为新类。这里有一个很受欢迎的问题(Convert column classes in data.table),但答案是创建一个新对象,而不是对起始对象进行操作。
举个例子:
function app_setup() {
options.database = 'testing';
it('app launched successfully', function(done) {
require('../app.js').initialize(0, options, function(err, app) {
remove_all_entities(function() {
app.set('port', port);
var server = app.listen(app.get('port'), function() {
console.log('Express server listening on port ' + server.address().port);
//ISSUE LOCATION, NEED TO CALL run_tests() callback after done()//
done();
run_tests();
});
});
});
});
}
function run_tests() {
var database = require('../database.js');
var entity_controller_test = require('./controllers/entity_controller_test.js').entity_controller_test;
var login_test = require('./controllers/login_test.js').login_test;
var token_access_test = require('./controllers/token_access_test.js').token_access_test;
var token_auth_test = require('./controllers/auth_token_test.js').token_auth_test;
var business_rules_insert = require('./business_rules/basic_database_rules.js').business_rules_insert_test;
var logout_test = require('./controllers/logout_test.js').logout_test;
var schema_override = require('./business_rules/schema_overrides').schema_overrides;
var aggregation_test = require('./entity_specific/aggregation').aggregation_test;
var tests = [login_test, aggregation_test, logout_test];
async.series(tests, function() {
test_teardown(done);
});
}
function test_teardown(done) {
remove_all_entities(done);
};
如何最好地将dat <- data.frame(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10))
cols <- c('ID', 'Quarter')
列转换为(例如)一个因素?在普通的data.frame中,你可以这样做:
cols
但这对data.table不起作用,而且
也不行dat[, cols] <- lapply(dat[, cols], factor)
来自Matt Dowle的链接问题(自2013年12月起)中的评论表明以下情况很好,但看起来不那么优雅。
dat[, .SD := lapply(.SD, factor), .SDcols = cols]
目前是否有更好的data.table答案(即较短的+没有生成计数器变量),或者我应该只使用上述+ for (j in cols) set(dat, j = j, value = factor(dat[[j]]))
?
答案 0 :(得分:39)
除了使用Matt Dowle建议的选项外,另一种更改列类的方法如下:
dat[, (cols) := lapply(.SD, factor), .SDcols = cols]
通过使用:=
运算符,您可以通过引用更新数据表。检查一下是否有效:
> sapply(dat,class)
ID Quarter value
"factor" "factor" "numeric"
正如@MattDowle在评论中所建议的那样,您还可以使用for(...) set(...)
的组合,如下所示:
for (col in cols) set(dat, j = col, value = factor(dat[[col]]))
将给出相同的结果。第三种选择是:
for (col in cols) dat[, (col) := factor(dat[[col]])]
在较小的数据集上,for(...) set(...)
选项比lapply
选项快三倍(但这并不重要,因为它是一个小数据集)。在较大的数据集(例如,200万行)上,这些方法中的每一种花费大约相同的时间量。为了测试更大的数据集,我使用了:
dat <- data.table(ID=c(rep("A", 1e6), rep("B",1e6)),
Quarter=c(1:1e6, 1:1e6),
value=rnorm(10))
有时,您必须以不同的方式执行此操作(例如,将数值存储为因子时)。然后你必须使用这样的东西:
dat[, (cols) := lapply(.SD, function(x) as.integer(as.character(x))), .SDcols = cols]
警告: 以下说明不 data.table
- 做事方式。数据表不是通过引用更新的,因为副本被创建并存储在内存中(如@Frank所指出的),这会增加内存使用量。这是为了解释with = FALSE
。
如果要以与使用数据框相同的方式更改列类,则必须按如下方式添加with = FALSE
:
dat[, cols] <- lapply(dat[, cols, with = FALSE], factor)
检查这是否有效:
> sapply(dat,class)
ID Quarter value
"factor" "factor" "numeric"
如果您不添加with = FALSE
,数据表会将dat[, cols]
评估为向量。检查dat[, cols]
和dat[, cols, with = FALSE]
之间的输出差异:
> dat[, cols]
[1] "ID" "Quarter"
> dat[, cols, with = FALSE]
ID Quarter
1: A 1
2: A 2
3: A 3
4: A 4
5: A 5
6: B 1
7: B 2
8: B 3
9: B 4
10: B 5
答案 1 :(得分:2)
您可以使用.SDcols
:
dat[, cols] <- dat[, lapply(.SD, factor), .SDcols=cols]