web-dev-qa-db-ja.com

条件値を使用したdplyr変異

4つの列を持つ大きなデータフレーム(「myfile」)では、最初の4つの列に基づいて条件付きで値を持つ5番目の列を追加する必要があります。

主に大規模なデータセットでの速度が理由で、dplyrおよびmutateで回答を優先します。

私のデータフレームは次のようになります。

  V1 V2 V3 V4
1  1  2  3  5
2  2  4  4  1
3  1  4  1  1
4  4  5  1  3
5  5  5  5  4
...

5番目の列(V5)の値は、いくつかの条件付きルールに基づいています。

if (V1==1 & V2!=4) {
  V5 <- 1
} else if (V2==4 & V3!=1) {
  V5 <- 2
} else {
  V5 <- 0
}

次に、mutate関数を使用して、すべての行でこれらのルールを使用します(低速ループを回避するため)。このようなもの(そして、はい、私はそれがこのように機能しないことを知っています!):

myfile <- mutate(myfile, if (V1==1 & V2!=4){V5 = 1}
    else if (V2==4 & V3!=1){V5 = 2}
    else {V5 = 0})

これは結果になるはずです:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

dplyrでこれを行う方法

63
rdatasculptor

これを試して:

myfile %>% mutate(V5 = (V1 == 1 & V2 != 4) + 2 * (V2 == 4 & V3 != 1))

与える:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

またはこれ:

myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, ifelse(V2 == 4 & V3 != 1, 2, 0)))

与える:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

注意

データフレームのより良い名前を取得することをお勧めします。 myfileは、ファイル名を保持しているように見せます。

上記はこの入力を使用しました:

myfile <- 
structure(list(V1 = c(1L, 2L, 1L, 4L, 5L), V2 = c(2L, 4L, 4L, 
5L, 5L), V3 = c(3L, 4L, 1L, 1L, 5L), V4 = c(5L, 1L, 1L, 3L, 4L
)), .Names = c("V1", "V2", "V3", "V4"), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5"))

更新1最初に投稿されたdplyrが%.%%>%に変更したため、それに応じて回答を変更しました。

更新2 dplyrには、別のソリューションを提供するcase_whenが追加されました。

myfile %>% 
       mutate(V5 = case_when(V1 == 1 & V2 != 4 ~ 1, 
                             V2 == 4 & V3 != 1 ~ 2,
                             TRUE ~ 0))
79
G. Grothendieck

dplyr 0.7.2を使用すると、非常に便利なcase_when関数を使用できます。

x=read.table(
 text="V1 V2 V3 V4
 1  1  2  3  5
 2  2  4  4  1
 3  1  4  1  1
 4  4  5  1  3
 5  5  5  5  4")
x$V5 = case_when(x$V1==1 & x$V2!=4 ~ 1,
                 x$V2==4 & x$V3!=1 ~ 2,
                 TRUE ~ 0)

dplyr::mutateで表され、以下を提供します。

x = x %>% mutate(
     V5 = case_when(
         V1==1 & V2!=4 ~ 1,
         V2==4 & V3!=1 ~ 2,
         TRUE ~ 0
     )
)

NAは誤解を招く可能性があるため、特別に扱われないことに注意してください。関数は、一致する条件がない場合にのみNAを返します。私の例で行ったように、TRUE ~ ...で行を配置すると、戻り値はNAになりません。

したがって、is.na(x$V1) | is.na(x$V3) ~ NA_integer_のようなステートメントを追加して、case_whenに明示的にNAを配置するように指示する必要があります。ヒント:ここでは、dplyr::coalesce()関数が本当に役立つ場合があります!

さらに、NAだけでは通常は機能しないことに注意してください。特別なNA値を挿入する必要があります:NA_integer_NA_character_またはNA_real_

18
Dan Chaltiel

derivedFactorパッケージのmosaicはこのために設計されたようです。この例では、次のようになります。

library(mosaic)
myfile <- mutate(myfile, V5 = derivedFactor(
    "1" = (V1==1 & V2!=4),
    "2" = (V2==4 & V3!=1),
    .method = "first",
    .default = 0
    ))

(結果を係数ではなく数値にする場合は、derivedFactoras.numericでラップします。)

.defaultオプションと.method = "first"を組み合わせて「else」条件を設定することに注意してください。このアプローチはderivedFactorのヘルプファイルで説明されています。

11
Jake Fisher