在data.table中转换* some *列类

时间:2015-10-05 02:45:40

标签: r data.table

我想将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]]))

2 个答案:

答案 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]