30

文字列と数値列を持つdata.frameの行に適用を使用する場合、applyはas.matrixを内部的に使用して、data.frameを文字のみに変換します。ただし、数値列が異なる長さの数値で構成されている場合、as.matrixは、最大/「最長」の数値に一致するようにスペースを追加します。

例:

df <- data.frame(id1=c(rep("a",3)),id2=c(100,90,8), stringsAsFactors = FALSE) 
df
##   id1 id2
## 1   a 100
## 2   a  90
## 3   a   8
as.matrix(df)
##      id1 id2  
## [1,] "a" "100"
## [2,] "a" " 90"
## [3,] "a" "  8"

結果は次のようになると思っていました。

     id1 id2  
[1,] "a" "100"
[2,] "a" "90"
[3,] "a" "8"

なぜ余分なスペース?

data.frameでapplyを使用すると、予期しない結果が生じる可能性があります。

myfunc <- function(row){
  paste(row[1], row[2], sep = "")
}
> apply(df, 1, myfunc)
[1] "a100" "a 90" "a  8"
> 

whileループを実行すると、期待どおりの結果が得られます。

> for (i in 1:nrow(df)){
  print(myfunc(df[i,]))
}
[1] "a100"
[1] "a90"
[1] "a8"

> paste(df[,1], df[,2], sep = "")
[1] "a100" "a90"  "a8"  

as.matrixで追加された余分なスペースが役立つ状況はありますか?

4

5 に答える 5

23

これは、メソッドで非数値データが変換されるas.matrix.data.frame方法が原因です。以下に示す簡単な回避策があります。

詳細

?as.matrixformat()変換はを介して行われ、ここにスペースが追加されることに注意してください。具体的には、詳細セクション?as.matrixにこれがあります。

 ‘as.matrix’ is a generic function.  The method for data frames
 will return a character matrix if there is only atomic columns and
 any non-(numeric/logical/complex) column, applying ‘as.vector’ to
 factors and ‘format’ to other non-character columns.  Otherwise,
 the usual coercion hierarchy (logical < integer < double <
 complex) will be used, e.g., all-logical data frames will be
 coerced to a logical matrix, mixed logical-integer will give a
 integer matrix, etc.

?formatまた、

文字列は、最も広い表示幅までブランクで埋められます。

動作を説明するこの例を考えてみましょう

> format(df[,2])
[1] "100" " 90" "  8"
> nchar(format(df[,2]))
[1] 3 3 3

formatそれが持っているようにこのように働く必要はありませんtrim

trim: logical; if ‘FALSE’, logical, numeric and complex values are
      right-justified to a common width: if ‘TRUE’ the leading
      blanks for justification are suppressed.

例えば

> format(df[,2], trim = TRUE)
[1] "100" "90"  "8"

しかし、この引数をメソッドに渡す方法はありませんas.matrix.data.frame

回避策

これを回避する方法はformat()、を介して手動で自分自身を適用することsapplyです。そこに渡すことができますtrim = TRUE

> sapply(df, format, trim = TRUE)
     id1 id2  
[1,] "a" "100"
[2,] "a" "90" 
[3,] "a" "8"

または、を使用しvapplyて、返されるものを指定できます(ここでは長さ3 [ nrow(df)]の文字ベクトル)。

> vapply(df, format, FUN.VALUE = character(nrow(df)), trim = TRUE)
     id1 id2  
[1,] "a" "100"
[2,] "a" "90" 
[3,] "a" "8"
于 2013-03-25T15:34:01.493 に答える
9

少し奇妙に思えます。マニュアル(?as.matrix)ではformat、文字マトリックスへの変換が必要であると説明されています。

データフレームのメソッドは、アトミック列と非(数値/論理/複合)列のみが存在する場合に文字行列を返し、as.vectorを因子に適用し、フォーマットを他の非文字列に適用します。

formatそして、あなたが直接電話をかけると、それが何をするかを見ることができますas.matrix

format(df$id2)
[1] "100" " 90" "  8"

あなたがする必要があるのは、trimarugmentを渡すことです:

format(df$id2,trim=TRUE)
[1] "100" "90"  "8" 

しかし、残念ながら、このas.matrix.data.frame関数ではそれができません。

else if (non.numeric) {
    for (j in pseq) {
        if (is.character(X[[j]])) 
            next
        xj <- X[[j]]
        miss <- is.na(xj)
        xj <- if (length(levels(xj))) 
            as.vector(xj)
        else format(xj) # This could have ... as an argument
        # else format(xj,...)
        is.na(xj) <- miss
        X[[j]] <- xj
    }
}

したがって、を変更できますas.data.frame.matrix。ただし、これをベースに含めると、機能が追加されるので便利だと思います。

ただし、簡単な解決策は次のとおりです。

as.matrix(data.frame(lapply(df,as.character)))
     id1 id2  
[1,] "a" "100"
[2,] "a" "90" 
[3,] "a" "8"  
# As mentioned in the comments, this also works:
sapply(df,as.character)
于 2013-03-25T15:37:41.643 に答える
6

as.matrixformat内部呼び出し:

 > format(df$id2)
[1] "100" " 90" "  8"

そこから余分なスペースが生まれます。それらを削除するためformatの追加の引数があります:trim

> format(df$id2, trim = TRUE)
[1] "100" "90"  "8"  

ただし、この引数をに指定することはできませんas.matrix

于 2013-03-25T15:34:54.473 に答える
1

この動作の理由は以前の回答ですでに説明されていますが、これを回避する別の方法を提供したいと思います。

df <- data.frame(id1=c(rep("a",3)),id2=c(100,90,8), stringsAsFactors = FALSE) 
do.call(cbind,df)
     id1 id2  
[1,] "a" "100"
[2,] "a" "90" 
[3,] "a" "8"  

stringsAsFactors = TRUEを使用する場合、因子レベルが数値に変換されるため、これは機能しないことに注意してください。

于 2013-03-25T19:40:17.937 に答える
0

ちょうど別の解決策:パッケージをダウンロードしてもかまわない場合は、trimWhiteSpace(x)(limma R pckgから)も機能します。

source("https://bioconductor.org/biocLite.R")
biocLite("limma")
library(limma)
df <- data.frame(id1=c(rep("a",3)),id2=c(100,90,8), stringsAsFactors = FALSE) 
as.matrix(df)
 id1 id2  
[1,] "a" "100"
[2,] "a" " 90"
[3,] "a" "  8"

trimWhiteSpace(as.matrix(df))
 id1 id2  enter code here
[1,] "a" "100"
[2,] "a" "90" 
[3,] "a" "8"
于 2018-05-03T02:03:55.460 に答える