web-dev-qa-db-ja.com

Rでのループを回避する方法:リストから項目を選択する

ループを使用してこれを解決することもできますが、コードをよりR風にするために、ベクトルで考えるようにしています。

名前のリストがあります。形式はfirstname_lastnameです。このリストから、名だけを含む別のリストを取得したいと思います。どうすればいいのか気になっていないようです。以下にデータの例をいくつか示します。

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- strsplit(t,"_")

これは次のようになります:

> tsplit
[[1]]
[1] "bob"   "smith"

[[2]]
[1] "mary" "jane"

[[3]]
[1] "jose"  "chung"

[[4]]
[1] "michael" "marx"   

[[5]]
[1] "charlie" "ivan"   

次のようなループを使用して、必要なものを取得できます。

for (i in 1:length(tsplit)){
    if (i==1) {t_out <- tsplit[[i]][1]} else{t_out <- append(t_out, tsplit[[i]][1])} 
}

これは私にこれを与えるでしょう:

t_out
[1] "bob"     "mary"    "jose"    "michael" "charlie"

では、ループなしでこれを行うにはどうすればよいですか?

31
JD Long

apply(またはsapply)を使用できます

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
f <- function(s) strsplit(s, "_")[[1]][1]
sapply(t, f)

bob_smith    mary_jane   jose_chung michael_marx charlie_ivan 

       "bob"       "mary"       "jose"    "michael"    "charlie" 

参照: Rの「適用」の簡単な紹介

26
liebke

そしてもう一つのアプローチ:

_t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
pieces <- strsplit(t,"_")
sapply(pieces, "[", 1)
_

つまり、最後の行はリストの各コンポーネントの最初の要素を抽出し、それをベクトルに簡略化します。

これはどのように作動しますか?まあ、あなたは_x[1]_を書く別の方法が"["(x, 1)であることを理解する必要があります。つまり、サブセット化を行う_[_という関数があります。 sapply呼び出しは、元のリストの要素ごとにこの関数を1回呼び出し、2つの引数(リスト要素と1)を渡します。

他の方法に対するこのアプローチの利点は、分割を再計算せずにリストから複数の要素を抽出できることです。たとえば、姓はsapply(pieces, "[", 2)になります。このイディオムに慣れると、非常に読みやすくなります。

43
hadley

どうですか:

tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
fnames <- gsub("(_.*)$", "", tlist)
# _.* matches the underscore followed by a string of characters
# the $ anchors the search at the end of the input string
# so, underscore followed by a string of characters followed by the end of the input string

regExアプローチについては?

10
William Doane

何について:

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")

sub("_.*", "", t)
9
Karsten

これが最もエレガントな解決策ではないかと思いますが、ループ処理に勝っています。

t.df <- data.frame(tsplit)
t.df[1, ]

リストをデータフレームに変換することは、リストを自分のやりたいことを実行させる唯一の方法です。リストの扱い方を実際に理解されている方の回答を楽しみにしています。

7
Matt Parker

あなたはそれをほとんど持っていました。それ本当にはただの問題です

  1. _*apply_関数の1つを使用して既存のリストをループします。私はlapplyで始まることが多く、場合によってはsapplyに切り替えます
  2. 一度に1つのリスト要素を操作する無名関数を追加する
  3. あなたはそれがstrsplit(string, splitterm)であることをすでに知っていて、答えの最初の項を選ぶには奇妙な_[[1]][1]_が必要であることを知っています
  4. 優先変数namne(tまたはcとその仲間たちから離れているため)から始めて、すべてをまとめます。

与える

_> tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan") 
> fnames <- sapply(tlist, function(x) strsplit(x, "_")[[1]][1]) 
> fnames 
  bob_smith    mary_jane   jose_chung michael_marx charlie_ivan   
      "bob"       "mary"       "jose"    "michael"    "charlie" 
>
_
4

unlist()を使用できます:

> tsplit <- unlist(strsplit(t,"_"))
> tsplit
 [1] "bob"     "smith"   "mary"    "jane"    "jose"    "chung"   "michael"
 [8] "marx"    "charlie" "ivan"   
> t_out <- tsplit[seq(1, length(tsplit), by = 2)]
> t_out
[1] "bob"     "mary"    "jose"    "michael" "charlie"

奇数インデックスのエントリのみを取得するより良い方法があるかもしれませんが、いずれにしてもループはありません。

3
brentonk

そして、ブレントンクの非公開の例に基づくもう1つのアプローチ...

tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- unlist(strsplit(tlist,"_"))
fnames <- tsplit[seq(1:length(tsplit))%%2 == 1]

2
William Doane

次のunlist()ベースのメソッドを使用します。

> t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
> tsplit <- strsplit(t,"_")
> 
> x <- matrix(unlist(tsplit), 2)
> x[1,]
[1] "bob"     "mary"    "jose"    "michael" "charlie"

この方法の大きな利点は、姓の同等の問題を同時に解決できることです。

> x[2,]
[1] "smith" "jane"  "chung" "marx"  "ivan" 

欠点は、すべての名前がfirstname_lastname構造に準拠していることを確認する必要があることです。もしそうでなければ、このメソッドは壊れます。

1
jmc200

最初に与えられた元のtsplitリストオブジェクトから、このコマンドは次のことを行います。

unlist(lapply(tsplit,function(x) x[1]))

すべてのリスト要素の最初の要素を抽出してから、リストをベクトルに変換します。最初にマトリックスへのリストを解除してから最初の列を抽出することもできますが、すべてのリスト要素が同じ長さであるという事実に依存しています。出力は次のとおりです。

> tsplit

[[1]]
[1] "bob"   "smith"

[[2]]
[1] "mary" "jane"

[[3]]
[1] "jose"  "chung"

[[4]]
[1] "michael" "marx"   

[[5]]
[1] "charlie" "ivan"   

> lapply(tsplit,function(x) x[1])

[[1]]
[1] "bob"

[[2]]
[1] "mary"

[[3]]
[1] "jose"

[[4]]
[1] "michael"

[[5]]
[1] "charlie"

> unlist(lapply(tsplit,function(x) x[1]))

[1] "bob"     "mary"    "jose"    "michael" "charlie"
0
Virginie