R でループを回避する方法:リストから項目を選択する
質問
ループを使用してこれを解決することもできますが、コードをより R らしくするためにベクトルで考えようとしています。
名前のリストがあります。形式は名_姓です。このリストからファーストネームのみを含む別のリストを取得したいと考えています。これをどうやって行うか、まったく思いつかないようです。データの例を次に示します。
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"
では、ループを使わずにこれを行うにはどうすればよいでしょうか?
解決
は、
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 の中で「適用」する
他のヒント
そして、もう一つのアプローチます:
t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
pieces <- strsplit(t,"_")
sapply(pieces, "[", 1)
の言葉では、最後の行は、リストの各構成要素の最初の要素を抽出し、ベクターにそれを単純化する。
これはどのように動作しますか? x[1]
はサブセット化を行う機能と呼ばれる"["(x, 1)
がある、すなわちさて、あなたは書き込み[
の代替方法を実現する必要があります。 sapply
コールは、二つの引数にリスト要素と1を渡し、元のリストの各要素に対して一度の呼び出しにこの機能を適用します。
他の人に対するこのアプローチの利点は、あなたが分割を再計算しなくても、リストから複数の要素を抽出することができるということです。たとえば、最後の名前はsapply(pieces, "[", 2)
されるだろう。あなたはこのイディオムに慣れたら、それは読み非常に簡単です。
いかがます:
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
正規表現のアプローチのために?
かについてます:
t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
sub("_.*", "", t)
私は、これが最もエレガントなソリューションです疑うが、それはループを打つます:
t.df <- data.frame(tsplit)
t.df[1, ]
データ・フレームにリストを変換すると、私は私がやりたいためにそれらを得ることができる唯一の方法についてです。私は実際にリストを処理する方法を理解する人によって答えを読んだことを楽しみにしています。
あなたはほとんどそれを持っていました。それ 本当に それはただの問題です
- のいずれかを使用して、
*apply
既存のリストをループする関数。私はよく次から始めます。lapply
そして時々に切り替えるsapply
- 一度にリスト要素の 1 つを操作する匿名関数を追加します。
- あなたはすでにそれを知っていました
strsplit(string, splitterm)
そして、あなたには奇妙なものが必要だということ[[1]][1]
答えの最初の項を取り出す - 優先変数 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"
>
あなたは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"
そこだけ奇数インデックスのエントリを引き出すには良い方法かもしれませんが、いずれにしてもあなたはループを持っていません。
そして、もう一つ別のアプローチ、brentonkの非公開に例をもとに...
tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- unlist(strsplit(tlist,"_"))
fnames <- tsplit[seq(1:length(tsplit))%%2 == 1]
Iは、以下の非公開に()を使用する - ベースの方法:
> 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
構造に適合していることを特定する必要がありますということです。いずれかがない場合、このメソッドは中断されます。
最初に与えられた元tsplit
リストオブジェクトから、このコマンドは実行します。
unlist(lapply(tsplit,function(x) x[1]))
はベクトルにリストを変換し、その後、すべてのリストの要素の最初の要素を抽出します。行列に最初Unlisting、そして拳列を抽出してもOKですが、あなたはすべてのリスト要素が同じ長さを有しているという事実に依存しています。ここで出力されます:
> 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"