web-dev-qa-db-ja.com

Rで一致する部分的な動物の文字列

データフレームがあります

d<-data.frame(name=c("brown cat", "blue cat", "big lion", "tall tiger",
                     "black panther", "short cat", "red bird",
                     "short bird stuffed", "big eagle", "bad sparrow",
                     "dog fish", "head dog", "brown yorkie",
                     "lab short bulldog"), label=1:14)

name列を検索したいのですが、「cat」、「lion」、「tiger」、「panther」という単語が表示された場合は、文字列felineを新しい列と対応する行species

単語"bird", "eagle", and "sparrow"が表示されたら、文字列avianを新しい列と対応する行speciesに割り当てます。

「dog」、「yorkie」、「bulldog」という単語が表示された場合、文字列canineを新しい列と対応する行speciesに割り当てます。

理想的には、これをリストまたはスクリプトの最初に残しておくことができる類似のものに保存します。種の新しいバリアントが名前のカテゴリに表示されるので、適格なものを更新するための簡単なアクセスがあるといいでしょう。 felineavian、およびcanineとして。

この質問はほぼここで回答されます(Rの他の列と一致する部分文字列に基づいてデータフレームに新しい列を作成する方法)、ただし、この問題に存在する複数の名前のツイストには対応していません。

16
testname123

これよりもエレガントな解決策があるかもしれませんが、grep|とともに使用して、代替の一致を指定できます。

d[grep("cat|lion|tiger|panther", d$name), "species"] <- "feline"
d[grep("bird|eagle|sparrow", d$name), "species"] <- "avian"
d[grep("dog|yorkie", d$name), "species"] <- "canine"

私はあなたが「鳥」を意味していると想定し、「ブルドッグ」には「犬」が含まれているので省略しました。

ignore.case = TRUEをgrepに追加することができます。

出力:

#                 name label species
#1           brown cat     1  feline
#2            blue cat     2  feline
#3            big lion     3  feline
#4          tall tiger     4  feline
#5       black panther     5  feline
#6           short cat     6  feline
#7            red bird     7   avian
#8  short bird stuffed     8   avian
#9           big eagle     9   avian
#10        bad sparrow    10   avian
#11           dog fish    11  canine
#12           head dog    12  canine
#13       brown yorkie    13  canine
#14  lab short bulldog    14  canine
26
ping

これを行うエレガントな方法(エレガントな方法と言いますが、これは私の知る限り最もエレガントな方法ですが、すばらしい方法ではありません)は次のようなものです。

#Define the regexes at the beginning of the code
regexes <- list(c("(cat|lion|tiger|panther)","feline"),
                c("(bird|eagle|sparrow)","avian"),
                c("(dog|yorkie|bulldog)","canine"))

....


#Create a vector, the same length as the df
output_vector <- character(nrow(d))

#For each regex..
for(i in seq_along(regexes)){

    #Grep through d$name, and when you find matches, insert the relevant 'tag' into
    #The output vector
    output_vector[grepl(x = d$name, pattern = regexes[[i]][1])] <- regexes[[i]][2]

} 

#Insert that now-filled output vector into the dataframe
d$species <- output_vector

この方法の利点はいくつかあります

  1. プロセス全体でデータフレームを1回変更するだけでよいので、ループの速度が向上します(データフレームにはインプレース変更がありません。データフレームを3回変更するには、基本的にラベルを付け直して再作成します3回)。
  2. ベクトルの長さを事前に指定することにより、それがどうなるかがわかっているので、出力ベクトルが作成された後に割り当てられるメモリを必要としないようにすることで、速度がさらに向上します。
  3. これは繰り返しの手動呼び出しではなくループであるため、「regexes」オブジェクトに行とカテゴリを追加しても、コードをさらに変更する必要はありません。今と同じように実行されます。

唯一の欠点-これは当てはまると思いますが、ほとんどの解決策は、何かが複数のパターンに一致する場合、一致するリストの最後のパターンが「種」タグになるということです。

2
user3471268