2016-08-30 16 views
3

私はいくつかの動物の避難訓練データでいくつかのデータクリーニングの練習を続けています。ここでの目標は、品種カテゴリの数を減らすことです。R:ネストされたifelseステートメントと複数のパターンを改善する

部分パターンマッチoutgoing$Single.Breedデータフレームの列とそれぞれの品種カテゴリを使用しています。だから、品種がChihuahuaになる場合もありますが、Long Hair Chihuahuaでもかまいません。 (したがって、私の使用はgreplです。)したがって、品種カテゴリを含むものは、そのカテゴリによって異なる列に表されます。さらに、私はまた、コードを追加する必要があります。 ...コードの作成がさらに複雑になります。

以下のコードは、「解決策」ですが、非常に厄介です。これを達成するためのより良い、より滑らかな、より効率的な方法がありますか?

BreedCategories <- ifelse(outgoing$New.Type == "Dog", 
      ifelse(grepl("Chihuahua",outgoing$Single.Breed, ignore.case = TRUE), "Chihuahua", 
      ifelse(grepl("Pit Bull",outgoing$Single.Breed, ignore.case = TRUE), "Pit Bull", 
      ifelse(grepl("Terrier",outgoing$Single.Breed, ignore.case = TRUE), "Terrier", 
      ifelse(grepl("Shepherd",outgoing$Single.Breed, ignore.case = TRUE), "Shepherd", 
      ifelse(grepl("Poodle",outgoing$Single.Breed, ignore.case = TRUE), "Poodle", 
      ifelse(grepl("Labrador|Retriever",outgoing$Single.Breed, ignore.case = TRUE),"Labrador", 
      "Other")))))),"Cat") 
+1

あなたの質問が[再現可能](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example)になるのに十分なデータを含める必要がありますが、チェックアウトしてください'dplyr :: case_when'。 – alistaire

+0

品種名がリストされているかどうかを確認しようとしているなら、 'ifelse'は必要ありません。再現可能な例とあなたの望む出力は理想的でしょう – Nate

答えて

4

正規表現と何品種が

map <- data.frame(
    pattern=c(
     "Chihuahua", "Pit Bull", "Terrier", "Shepherd", 
     "Poodle", "Labrador|Retriever", "Other"), 
    isa=c(
     "Chihuahua", "Pit Bull", "Terrier", "Shepherd", 
     "Poodle", "Labrador", "Other"), 
    stringsAsFactors=FALSE) 

であり、プログラムのためのいくつかのデータ

outgoing <- data.frame(Single.Breed=c(map$isa, "Pit Bull Poodle", "Pug"), 
         stringsAsFactors=FALSE) 

間のマップdata.frameを作成し、一致するvapply()grepl()を使用各パターンをデータに適用する。 grepl()の使用は、結果は、各行を訪問し、存在する場合「その他」であることを起こる最高の(最後の)一致する(取得するために、各エントリに対応する行

isa <- vapply(map$pattern, grepl, logical(nrow(outgoing)), outgoing$Single.Breed) 
if (any(rowSums(isa) > 1)) 
    warning("ambiguous breeds: ", outgoing$Single.Breed[rowSums(isa) != 1]) 

使用max.col()と、マトリックスであることを意味しますマッチなし)。

outgoing$BreedCategory <- map$isa[max.col(isa, "last")] 

は、ここで私はそれがより明確に「プログラム」(grepl()max.col())から「データ」(正規表現と入力品種)を分離するのでアプローチが魅力的だと思い結果

> isa <- vapply(map$pattern, grepl, logical(nrow(outgoing)), outgoing$Single.Breed) 
> if (any(rowSums(isa) > 1)) 
+  warning("ambiguous breeds: ", outgoing$Single.Breed[rowSums(isa) != 1]) 
Warning message: 
ambiguous breeds: Pit Bull Poodle 
> outgoing$BreedCategory <- map$isa[max.col(isa, "last")] 
> outgoing 
    Single.Breed BreedCategory 
1  Chihuahua  Chihuahua 
2  Pit Bull  Pit Bull 
3   Terrier  Terrier 
4  Shepherd  Shepherd 
5   Poodle  Poodle 
6  Labrador  Labrador 
7   Other   Other 
8 Pit Bull Poodle  Poodle 
9    Pug   Other 

です。

「その他」の扱いが少し壊れやすいように見えますが、それがmapの最後の要素であることを忘れてしまったらどうなりますか?一つの可能​​性は、効率的で非常にスペースない(マトリックスがNX位に自分の長さNのデータを変換ISAの行の合計をテストインジケータ変数を作成し、そして上記

test = rowSums(isa) 
outgoing$BreedCategory[test == 0] = "Other" 
outgoing$BreedCategory[test == 1] = map$isa[max.col(isa)][test == 1] 
outgoing$BreedCategory[test > 1] = "Mixed" 

条件付き品種を割り当てるために、これを使用して正規表現マトリックスの)しかし、1Mの入力行を言う仕事をする可能性が高いようです。

dplyr::case_when()は、多くの場合、エラーが発生しやすいgrepl()文を書く必要があるようです。

+0

私はこれが好きです。' map $ isa [max。col(isa、 "first")] '' apply'ステートメントを避けます。 – thelatemail

+0

@thelatemailありがとう!私は 'max.col()'について知らないことを認めます( 'max.row()'が存在しないということは奇妙です)。 –

+0

ありがとうございます!これは非常に役に立ち、仕事を終えました!これは間違いなく、将来の使用のために私のRツールボックスに追加する別の巧妙な戦略になるでしょう!私は、「その他」はかなり壊れやすいことに同意します。インジケータ変数は、スペースの非効率性を無視して、それを解決する良い方法です。幸運なことに、私のデータセットは大規模ではないので、必要に応じてその変数は確実にオプションになります。 – kimbekaw

関連する問題