基于后缀匹配的不整洁数据中的新变量

时间:2018-09-03 09:29:07

标签: r

我想重组我的数据框,其中包含有关是否查看,购买或出售房屋以及查看/购买/出售日期的数据。

以这样一种方式输入数据:尽管存在多个日期变量(var_datevar_A5_3_B32var_datevar_A5_4_B33var_datevar_A5_5_B34),但是这些变量中的每一个都包含销售日期的混合,购买日期和查看日期。

因此,如果想知道例如var_datevar_A5_3_B32中的日期是观看,销售或购买日期,我需要检查具有匹配前缀(A5_3_B32)的变量,即var_viewed_A5_3_B32,{ {1}}和var_sold_A5_3_B32,然后查看哪个编码为“ Y”。

我想在数据框中添加三个新变量:仅销售日期变量(var_purchased_A5_3_B32),仅购买日期变量(var_date_sold)和仅观看日期变量( var_date_purchased),就像在var_date_viewed中一样。

我已经尝试过,但除此之外,我无法弄清楚如何将日期粘贴到新变量中,我想要一个更通用的解决方案,因为在我的真实数据集中,我有很多变量像这样。

感谢您的帮助!

dfgoal

1 个答案:

答案 0 :(得分:0)

使用软件包dplyrtidyrstringr的另一种方法:

library(tidyr)
library(dplyr)
library(stringr)

df %>% 
  gather(datevar, date, contains("datevar")) %>%
  gather(action, action_yn, -datevar, -date, -var_home) %>%
  mutate(date_code = str_extract(datevar, "A\\d_\\d_B\\d\\d$"),
         action_code = str_extract(action, "A\\d_\\d_B\\d\\d$"), 
         action = str_extract(action, "^var_[[a-z][^_]]+"), 
         action = str_remove(action, "^var_")) %>% 
  filter(date_code == action_code) %>% 
  filter(action_yn == "Y") %>% 
  select(-datevar) %>% 
  group_by(var_home, action) %>% 
  summarise(date = str_c(date, collapse = ",")) %>% 
  mutate(action = str_c("var_date_", action)) %>% 
  spread(action, date)

# A tibble: 5 x 4
# Groups:   var_home [5]
#   var_home var_date_purchased var_date_sold var_date_viewed                 
#   <fct>    <chr>              <chr>         <chr>                           
# 1 a        05-03-2013         07-12-2012    01-12-2012                      
# 2 b        05-06-2014         NA            NA                              
# 3 c        07-07-2017         NA            03-09-2015                      
# 4 d        NA                 NA            03-03-2016,13-03-2016,23-03-2016
# 5 e        NA                 NA            NA        

我将代码分成几部分来解释,该怎么做。
首先将数据从宽格式转换为长格式,然后首先将所有datvar收集起来,然后将所有操作一起包含在一个列中,每个列都具有对应的值(dateaction_yn)。

df <- df %>% 
  gather(datevar, date, contains("datevar")) %>%
  gather(action, action_yn, -datevar, -date, -var_home)

df
#     var_home              datevar       date                 action action_yn
# 1          a var_datevar_A5_3_B32 01-12-2012 var_purchased_A5_3_B32      <NA>
# 2          b var_datevar_A5_3_B32 05-06-2014 var_purchased_A5_3_B32         Y
# 3          c var_datevar_A5_3_B32 03-09-2015 var_purchased_A5_3_B32      <NA>
# 4          d var_datevar_A5_3_B32 03-03-2016 var_purchased_A5_3_B32      <NA>
# 5          e var_datevar_A5_3_B32       <NA> var_purchased_A5_3_B32      <NA>
# ...

然后使用正则表达式提取代码(每个列名称的最后一部分)。在这里,我假设这总是像A#_#_ B ##那样构造,其中#是数字。此外,使用常规表达式再次提取特定动作。

df <- df %>%
  mutate(date_code = str_extract(datevar, "A\\d_\\d_B\\d\\d$"),
         action_code = str_extract(action, "A\\d_\\d_B\\d\\d$"), 
         action = str_extract(action, "^var_[[a-z][^_]]+"), 
         action = str_remove(action, "^var_")) 

df
#     var_home              datevar       date    action action_yn date_code action_code
# 1          a var_datevar_A5_3_B32 01-12-2012 purchased      <NA>  A5_3_B32    A5_3_B32
# 2          b var_datevar_A5_3_B32 05-06-2014 purchased         Y  A5_3_B32    A5_3_B32
# 3          c var_datevar_A5_3_B32 03-09-2015 purchased      <NA>  A5_3_B32    A5_3_B32
# 4          d var_datevar_A5_3_B32 03-03-2016 purchased      <NA>  A5_3_B32    A5_3_B32
# 5          e var_datevar_A5_3_B32       <NA> purchased      <NA>  A5_3_B32    A5_3_B32
# ...

因为我们只对带有“ Y”的动作感兴趣,并且只对与正确动作相对应的日期进行了编码和action_yn的过滤。 datevar不再需要,因此被删除。

df <- df %>% 
  filter(date_code == action_code) %>% 
  filter(action_yn == "Y") %>% 
  select(-datevar) 

df
#     var_home       date    action action_yn date_code action_code
#  1         b 05-06-2014 purchased         Y  A5_3_B32    A5_3_B32
#  2         c 07-07-2017 purchased         Y  A5_4_B33    A5_4_B33
#  3         a 05-03-2013 purchased         Y  A5_5_B34    A5_5_B34
#  4         a 01-12-2012    viewed         Y  A5_3_B32    A5_3_B32
#  5         c 03-09-2015    viewed         Y  A5_3_B32    A5_3_B32
#  6         d 03-03-2016    viewed         Y  A5_3_B32    A5_3_B32
#  7         d 13-03-2016    viewed         Y  A5_4_B33    A5_4_B33
#  8         d 23-03-2016    viewed         Y  A5_5_B34    A5_5_B34
#  9         a 07-12-2012      sold         Y  A5_4_B33    A5_4_B33
# 10         e       <NA>      sold         Y  A5_5_B34    A5_5_B34

最后,对于每个var_home和每个action,将日期粘贴在一起(如果有多个日期),将操作重命名(以获得所需的最终列名),然后将每个操作散布到自己的列(带有spread):

df <- df %>% 
  group_by(var_home, action) %>% 
  summarise(date = str_c(date, collapse = ",")) %>% 
  mutate(action = str_c("var_date_", action)) %>% 
  spread(action, date)

如果您希望将此信息与原始数据一起存储,请假定将其存储在df_org中。然后,您可以使用join

left_join(df_org, df, by = "var_home")
#   var_home var_datevar_A5_3_B32 var_datevar_A5_4_B33  ...  var_sold_A5_4_B33 var_sold_A5_5_B34 var_date_purchased var_date_sold var_date_viewed
# 1        a           01-12-2012           07-12-2012  ...  Y                 N                 05-03-2013         07-12-2012    01-12-2012
# 2        b           05-06-2014                 <NA>  ...  N                 <NA>              05-06-2014         <NA>          <NA>
# 3        c           03-09-2015           07-07-2017  ...  <NA>              <NA>              07-07-2017         <NA>          03-09-2015
# 4        d           03-03-2016           13-03-2016  ...  N                 <NA>              <NA>               <NA>          03-03-2016,13-03-2016,23-03-2016
# 5        e                 <NA>                 <NA>  ...  <NA>              Y                 <NA>               <NA>          <NA>