NA のフィルタリング方法にバグがあると思いMonetDB.R
ます。以下のコード例を参照してください。
オブジェクトに対して一般的な SQL クエリを実行するための便利なユーティリティ関数monet.frame
:
#' Apply general SQL queries to a monet.frame object and return the
#' result in a new monet.frame.
#'
#' @note Likely to break if \code{attr(data, "query")} contains
#' LIMIT or OFFSET statements.
#'
#' @param _data a monet.frame object
#' @param query an SQL query, using "_DATA_" as the placeholder for the
#' name of the table underlying the \code{_data}-object.
#' @param keep_order should ORDER BY statements in the original query be kept?
#' Will break if columns in the ORDER BY statement are not in the returned
#' table.
#' @importFrom stringr str_extract_all
#' @export
transform.monet.frame <- function(`_data`, query, keep_order=TRUE, ...){
stopifnot(require(stringr))
nm <- paste(sample(letters, 15, rep=TRUE), collapse="")
oldquery <- attr(`_data`, "query")
if(has_order <- grepl("(ORDER BY)", attr(`_data`, "query"))){
pattern <- "(ORDER BY[[:space:]]+[[:alnum:]]+((,[[:space:]]*[[:alnum:]]+)*))"
pattern <- ignore.case(pattern)
orderby <- str_extract_all(oldquery, pattern)[[1]]
oldquery <- gsub(pattern, "", oldquery, ignore.case = TRUE)
}
query <- gsub("_DATA_", paste("(", oldquery, ") AS", nm), query)
if(has_order & keep_order) query <- paste(query, orderby)
monet.frame(attr(`_data`, "conn"), query)
}
例:
# library(MonetDB.R); monetdb <- dbConnect( MonetDB.R(), ... etc
set.seed(1212)
tablename <- paste(sample(letters, 10), collapse="")
data <- data.frame(x=rnorm(100), f=gl(2, 50))
# introduce some NAs ...
data$xna <- data$x
data$xna[1:10] <- NA
dbWriteTable(monetdb, tablename, data)
dm <- monet.frame(monetdb, tablename)
str(na.omit(dm$xna))
# MonetDB-backed data.frame surrogate
# 1 column, 100 rows
# Query: SELECT xna FROM gcxinabtme WHERE ( NOT (('xna') IS NULL) )
# Columns: xna (numeric)
100行!? 90のはず...
nrow(transform(dm, "SELECT xna FROM _DATA_ WHERE (xna IS NOT NULL)"))
# 90
## as it should be
nrow(transform(dm, "SELECT xna FROM _DATA_ WHERE ('xna' IS NOT NULL)"))
# 100
## so quoting the column name seems to mess this up..
列名を引用する必要がある理由を理解していると思います (したがって、これは非標準の列名でも機能しますよね?) が、なぜこれがクエリ結果を台無しにするのでしょうか? これら 2 つは完全に同等のクエリであるべきではありませんか? xna
また、列名を引用する必要がある場合、最初に引用されていないのはなぜですか
# Query: SELECT xna FROM gcxinabtme WHERE ( NOT (('xna') IS NULL) )
これは、他のmonet.frame
メソッドも予期しない動作をさせるためです。たとえば、次のようになります。
quantile(dm$xna, na.rm=TRUE)
# 0% 25% 50% 75% 100%
# NA -0.9974738 -0.3033412 0.4272321 2.6715264
編集して追加:
na.fail
同様に壊れているようです:
エラーは発生しませんが、代わりに NA を保持する列に適用されると NULL を返し、実際には NA が存在しないことを一目で示す不可解な警告が表示されます。
str(na.fail(dm$xna))
# NULL
# Warning message:
# In monet.frame.internal(attr(x, "conn"), nquery, .is.debug(x), nrow.hint = NA, :
# SELECT xna FROM gcxinabtme WHERE ( ('xna') IS NULL ) has zero-row result set.
NA がない場合na.fail()
、ジェネリックのドキュメントに従って引数を変更せずに返す必要がありますが、それも行いません。
str(na.fail(dm$x))
# NULL
# Warning message:
# In monet.frame.internal(attr(x, "conn"), nquery, .is.debug(x), nrow.hint = NA, :
# SELECT x FROM gcxinabtme WHERE ( ('x') IS NULL ) has zero-row result set.