12

Codd の第 3 正規形を満たすために、2 つのテーブルに分割する必要があるデータ フレームがあります。単純なケースでは、元のデータ フレームは次のようになります。

library(lubridate)
> (df <- data.frame(hh_id = 1:2,
                   income = c(55000, 94000),
                   bday_01 = ymd(c(20150309, 19890211)),
                   bday_02 = ymd(c(19850911, 20000815)),
                   gender_01 = factor(c("M", "F")),
                   gender_02 = factor(c("F", "F"))))

    hh_id income    bday_01    bday_02 gender_01 gender_02
  1     1  55000 2015-03-09 1985-09-11         M         F
  2     2  94000 1989-02-11 2000-08-15         F         F

収集機能を使用すると、属性が同一ではなく、性別の要素と誕生日の潤滑油 (または実際の例では他の属性) が失われることが警告されます。各列のデータ型が失われないようにするための適切なソリューションはありますか?

library(tidyr)
> (person <- df %>% 
      select(hh_id, bday_01:gender_02) %>% 
      gather(key, value, -hh_id) %>%
      separate(key, c("key", "per_num"), sep = "_") %>%
      spread(key, value))

     hh_id per_num       bday gender
   1     1      01 1425859200      M
   2     1      02  495244800      F
   3     2      01  603158400      F
   4     2      02  966297600      F

   Warning message:
   attributes are not identical across measure variables; they will be dropped

> lapply(person, class)

  $hh_id
  [1] "integer"

  $per_num
  [1] "character"

  $bday
  [1] "character"

  $gender
  [1] "character"

同じデータ型の変数の各セットを個別に収集してからすべてのテーブルを結合する方法を想像できますが、私が見逃しているより洗練されたソリューションがあるはずです。

4

3 に答える 3

15

日付を文字に変換し、最後に日付に戻すことができます。

(person <- df %>% 
      select(hh_id, bday_01:gender_02) %>% 
      mutate_each(funs(as.character), contains('bday')) %>%
      gather(key, value, -hh_id) %>%
      separate(key, c("key", "per_num"), sep = "_") %>%
      spread(key, value) %>%
      mutate(bday=ymd(bday)))

  hh_id per_num       bday gender
1     1      01 2015-03-09      M
2     1      02 1985-09-11      F
3     2      01 1989-02-11      F
4     2      02 2000-08-15      F

あるいは、Dateの代わりにを使用する場合は、次のPOSIXctようにすることもできます。

(person <- df %>% 
      select(hh_id, bday_01:gender_02) %>% 
      gather(per_num1, gender, contains('gender'), convert=TRUE) %>%
      gather(per_num2, bday, contains('bday'), convert=TRUE) %>%
      mutate(bday=as.Date(bday)) %>%
      mutate_each(funs(str_extract(., '\\d+')), per_num1, per_num2) %>%
      filter(per_num1 == per_num2) %>%
      rename(per_num=per_num1) %>%
      select(-per_num2))

編集

表示される警告:

Warning: attributes are not identical across measure variables; they will be dropped

因子であり、さまざまなレベル ベクトルを持つ性別の列を収集することで発生します ( を参照str(df))。性別の列をキャラクターに変換する場合、またはレベルを次のように同期する場合は、

df <- mutate(df, gender_02 = factor(gender_02, levels=levels(gender_01)))

次に、実行すると警告が消えることがわかります

person <- df %>% 
        select(hh_id, bday_01:gender_02) %>% 
        gather(key, value, contains('gender'))
于 2015-03-10T20:11:41.053 に答える