web-dev-qa-db-ja.com

データフレームの行を連結する

文字と数字を含むデータフレームを取得し、各行のすべての要素を単一の文字列に連結して、ベクトル内の単一の要素として保存したいと思います。例として、文字と数字のデータフレームを作成してから、貼り付け関数を使用して最初の行を連結し、できれば値「A1」を返したいと思います。

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5)
df

##   letters numbers
## 1       A       1
## 2       B       2
## 3       C       3
## 4       D       4
## 5       E       5

paste(df[1,], sep =".")
## [1] "1" "1"

したがって、貼り付けは、行の各要素を「対応するレベルのインデックス」に対応する整数に変換し、あたかも因子であるかのように変換し、長さ2のベクトルを保持します。 (文字に強制される因子はこのように振る舞うことを知っていますが、Rはdf [1、]を因子としてまったく保存していないため(is.factor()でテスト済みです)、それを確認できません実際にはレベルのインデックスです)

is.factor(df[1,])
## [1] FALSE
is.vector(df[1,])
## [1] FALSE

それがベクトルでない場合、それは奇妙に振る舞っていることは理にかなっていますが、私はそれをベクトルに強制することはできません

> is.vector(as.vector(df[1,]))
[1] FALSE

as.characterを使用しても、私の試みには役に立たなかった

誰でもこの動作を説明できますか?

29
Sam

他の人はあなたのコードが機能しない理由とそれを改善する方法に焦点を合わせていますが、私はあなたが望む結果を得ることにもっと集中しようとします。あなたの説明から、あなたはペーストを使ってあなたが望むものをすぐに達成できるようです:

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=FALSE)
paste(df$letters, df$numbers, sep=""))

## [1] "A1" "B2" "C3" "D4" "E5"

stringsAsFactors引数を使用したくない場合は、df$letters <- as.character(df$letters)を使用してdf$lettersを文字に変更できます。

しかし、それはあなたが望むものではないと仮定しましょう。何百もの列があり、それらをすべて一緒に貼り付けたいとします。あなたの最小限の例でもそれを行うことができます:

df_args <- c(df, sep="")
do.call(paste, df_args)

## [1] "A1" "B2" "C3" "D4" "E5"

編集:別の方法と説明:

あなたが持っている問題は、ファクタを使用していることと、sepの代わりにcollapse引数を使用しているという事実の組み合わせであることに気付きました(@adibenderが選択したように) 。違いは、sepは2つの別々のベクトル間のセパレーターを提供し、collapseはベクター内のセパレーターを提供することです。 df[1,]を使用する場合、pasteに単一のベクトルを指定するため、collapse引数を使用する必要があります。すべての行を取得してそれらを連結するという考えを使用して、次のコード行はまさにあなたが望むことをします:

apply(df, 1, paste, collapse="")

さて、説明のために:

なぜas.listが機能しないのですか?

as.listは、オブジェクトをリストに変換します。それで動作します。データフレームをリストに変換し、その後sep=""引数を無視します。 cはオブジェクトを結合します。技術的には、データフレームは単なるリストであり、すべての列が要素であり、すべての要素は同じ長さでなければなりません。したがって、それをsep=""と組み合わせると、データフレームの列を要素として持つ通常のリストになります。

do.callを使用する理由

do.callを使用すると、名前付きリストを引数として使用して関数を呼び出すことができます。リストをpasteに直接投げ込むことはできません。データフレームが好きではないからです。ベクトルを連結するために設計されています。したがって、dfargsは文字のベクトル、数字のベクトル、および「」のみを含む長さ1のベクトルを含むsepを含むリストであることを忘れないでください。 do.callを使用すると、結果の貼り付け関数は基本的にpaste(letters, numbers, sep)です。
しかし、元のデータフレームに"letters", "numbers", "squigs", "blargs"列があり、その後に以前のようにセパレータを追加した場合はどうなりますか?次に、do.callを介した貼り付け関数は次のようになります。

paste(letters, numbers, squigs, blargs, sep)

したがって、任意の数の列で機能することがわかります。

54
sebastian-c

これは確かに少し奇妙ですが、これも起こるはずです。 _data.frame_を作成したとき、列lettersfactorとして保存されます。当然、因子には順序がありません。したがって、as.numeric()が因子に適用されると、因子の順序が返されます。例えば:

_> df[, 1]
[1] A B C D E
Levels: A B C D E
> as.numeric(df[, 1])
[1] 1 2 3 4 5
_

Aは、因子_df[, 1]_の最初のレベルです。したがって、Aは、_1_が適用されると、値_as.numeric_に変換されます。 paste(df[1, ])を呼び出すと、これが起こります。列1と列2は異なるクラスであるため、貼り付けでは最初に行1の両方の要素が数値に変換され、次に文字に変換されます。

両方の列を連結する場合、最初の行を文字に変換する必要があります。

_df[, 1] <- as.character(df[, 1])
paste(df[1,], collapse = "")
_

@ sebastian-cが指摘したように、data.frameの作成で_stringsAsFactors = FALSE_を使用することもできます。その後、as.character()ステップを省略できます。

4
adibender

Library(tidyverse)を使用している場合は、単純にunite関数を使用できます。

 new.df<-df%>%
 unite(together, letters, numbers, sep="")

これにより、A1、B2などと「一緒に」という新しい列が表示されます。

4
Shirley

で始めたいなら

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=TRUE)

..その後、df$lettersは、任意の関数によって解釈されます。これは、モデリング関数、一部の文字、その他の整数の要素です。貼り付けなどの同じ機能でも、使用方法に応じて解釈が異なる場合があります。

paste(df[1,], collapse="") # "11"
apply(df, 1, paste, collapse="") # "A1" "B2" "C3" "D4" "E5"

すべての関数の内部を知っていれば、おそらく理にかなっていることを除いて、その中にロジックはありません。

引数がベクトルに変換されると、係数は整数に変換されるようです(ご存じのように、データフレームは長さが等しいベクトルのリストです。そのため、データフレームの最初の行もリストであり、ベクトル、このようなことが起こります:)

df[1,]
#    letters numbers
# 1       A       1
unlist(df[1,])
# letters numbers 
#  1       1 

applyがどのように機能するかわかりません(つまり、因子は文字値で表されます)-もし興味があるなら、そのソースコードを見てください。ただし、(この特定の意味で)apply(この特定の場合)を信頼できることを知っておくと便利です。より一般的には、すべてのデータを適切な形式で保存すると便利です。これには、文字列としての文字列の保存が含まれます。つまり、stringsAsFactors=FALSE

ところで、すべての入門R本には、サブタイトルにこの考えが必要です。たとえば、私の退職の計画は、「Rを使用した禅のデータ漁業の(それほどではない)優しい紹介、stringsAsFactors = FALSE way」と書くことです。

1
lebatsnok