我在data.table中找到了一些关于特定列名称的尖锐边缘。我怎样才能避免割伤自己?假设我有一个data.table,有两列,'type'和'value'。
numRows = 100
numTypes = 10
dt = data.table(type=sample(numTypes, numRows, replace=T),
value=rnorm(numRows))
如果我想快速计算类型== 3的所有行的平均值,那么效果很好:
dt[type==3, mean(value)]
# [1] 0.08086124
但是,如果“不是我的人”出现并决定“类型”对于专栏来说是一个糟糕的名称,那么它应该是一个“类”吗?
setnames(dt, "type", "class")
现在,当我尝试等效操作时,我收到了可怕的错误消息:
dt[class==3, mean(value)]
# Error in setattr(attr(x, "index"), paste(cols, collapse = "__"), o) :
# attempt to set invalid 'class' attribute
我预期的行为(OSX上的1.9.4)?我认为它发生是因为'class'是R中的函数名,而data.table内部的东西正在解释它。在括号中包装i子句似乎解决了这个问题:
dt[(class==3), mean(value)]
# [1] 0.08086124
但也许有些情况下这种解决方法也失败了?
在这种情况下,是否存在预计会失败的列名列表?
用户定义的函数或加载的库是否会导致相同的错误?
一般来说,我应该使用哪种更安全的方法吗?
答案 0 :(得分:2)
这似乎已经解决了。更新您的data.table包。
function print_r_reverse($in) {
$lines = explode("\n", trim($in));
if (trim($lines[0]) != 'Array') {
// bottomed out to something that isn't an array
return $in;
} else {
// this is an array, lets parse it
if (preg_match("/(\s{5,})\(/", $lines[1], $match)) {
// this is a tested array/recursive call to this function
// take a set of spaces off the beginning
$spaces = $match[1];
$spaces_length = strlen($spaces);
$lines_total = count($lines);
for ($i = 0; $i < $lines_total; $i++) {
if (substr($lines[$i], 0, $spaces_length) == $spaces) {
$lines[$i] = substr($lines[$i], $spaces_length);
}
}
}
array_shift($lines); // Array
array_shift($lines); // (
array_pop($lines); // )
$in = implode("\n", $lines);
// make sure we only match stuff with 4 preceding spaces (stuff for this array and not a nested one)
preg_match_all("/^\s{4}\[(.+?)\] \=\> /m", $in, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
$pos = array();
$previous_key = '';
$in_length = strlen($in);
// store the following in $pos:
// array with key = key of the parsed array's item
// value = array(start position in $in, $end position in $in)
foreach ($matches as $match) {
$key = $match[1][0];
$start = $match[0][1] + strlen($match[0][0]);
$pos[$key] = array($start, $in_length);
if ($previous_key != '') $pos[$previous_key][1] = $match[0][1] - 1;
$previous_key = $key;
}
$ret = array();
foreach ($pos as $key => $where) {
// recursively see if the parsed out value is an array too
$ret[$key] = print_r_reverse(substr($in, $where[0], $where[1] - $where[0]));
}
return $ret;
}
}