使用pivot_longer将宽列聚集为多个长列

时间:2019-09-28 11:24:50

标签: r tidyr

我有一些代码,可以通过收集从宽转换为长,但是我必须逐列进行。我想使用pivot_longer将宽的多列收集为多个长列,而不是逐列。

例如,列hf_1,hf_2,hf_3,hf_4,hf_5,hf_6需要旋转为2列(hf_com-该列,其值分别来自宽hf列的1,2,3,4,5,6)和(hf_com_freq-该列的值为1)。

对于列ac_1,ac_2,ac_3,ac_4,ac_5,ac_6,同样需要发生。这些列需要分为2列(ac_com-该列具有来自宽ac列的值1,2,3,4,5,6)和(ac_com_freq-该列具有值1)。

对于列cs_1,cs_2,cs_3,cs_4,cs_5,cs_6,cs_7,cs_8,也需要进行相同的操作。这些列需要分为2列(cur_sal-宽cs列的值为1,2,3,4,5,6,7,8的列)和(curr_sal_freq-值为1的此列)。

对于列se_1,se_2,se_3,se_4,se_5,se_6,se_7,se_8,同样需要发生。这些列需要分为2列(exp_sal-该列具有来自se值的1,2,3,4,5,6,7,8的值)和(exp_sal_freq-该列具有值1的值)

我尝试查看:

Gather multiple sets of columns

和:

Reshaping multiple sets of measurement columns (wide format) into single columns (long format)

但是我无法获得所需的多个较长的列。

以下是输入数据:

structure(list(np_id = c("81", "83", "85", "88", "1", "2"), np_look_work = c("yes", 
"yes", "yes", "yes", "yes", "yes"), np_current_work = c("no", 
"yes", "no", "no", "no", "no"), np_before_work = c("no", "NULL", 
"yes", "yes", "yes", "yes"), np_keen_move = c("yes", "yes", "no", 
"no", "no", "no"), np_city_size = c("village", "more than 500k inhabitants", 
"more than 500k inhabitants", "village", "city up to 20k inhabitants", 
"100k - 199k inhabitants"), np_gender = c("male", "female", "female", 
"male", "female", "male"), np_age = c("18 - 24 years", "18 - 24 years", 
"more than 50 years", "18 - 24 years", "31 - 40 years", "more than 50 years"
), np_education = c("secondary", "vocational", "secondary", "secondary", 
"secondary", "secondary"), hf_1 = c(NA, NA, NA, "1", "1", "1"
), hf_2 = c(NA, "1", "1", NA, NA, NA), hf_3 = c(NA_character_, 
NA_character_, NA_character_, NA_character_, NA_character_, NA_character_
), hf_4 = c(NA_character_, NA_character_, NA_character_, NA_character_, 
NA_character_, NA_character_), hf_5 = c(NA_character_, NA_character_, 
NA_character_, NA_character_, NA_character_, NA_character_), 
    hf_6 = c(NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_), ac_1 = c(NA, NA, NA, NA, NA, 
    "1"), ac_2 = c(NA, "1", "1", NA, "1", NA), ac_3 = c(NA, NA, 
    NA, NA, "1", NA), ac_4 = c(NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_
    ), ac_5 = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_), ac_6 = c(NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_), cs_1 = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_), cs_2 = c(NA, 
    "1", "1", NA, "1", NA), cs_3 = c(NA, NA, NA, NA, NA, "1"), 
    cs_4 = c(NA, NA, NA, "1", NA, NA), cs_5 = c(NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_), cs_6 = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_), cs_7 = c(NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_), cs_8 = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_), se_1 = c(NA, 
    NA, "1", "1", NA, NA), se_2 = c(NA, NA, NA, NA, "1", NA), 
    se_3 = c(NA, "1", NA, NA, "1", "1"), se_4 = c(NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_), se_5 = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_), se_6 = c(NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_), se_7 = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_), se_8 = c(NA, 
    NA, NA, "1", NA, NA)), row.names = c(NA, 6L), class = "data.frame")

这是我尝试的代码:

# Read CSV into R
###
MyData <- read.csv(file="task.csv", header=TRUE, sep=",", stringsAsFactors = F)
# str(MyData)

# set as general option that Strings are not factors
options(stringsAsFactors = FALSE)

# save all column names
old_names1 <- colnames(MyData)
new_names1 = c("np_id","np_look_work", "np_current_work",
              "hf_1", "ac_1", 
              "hf_2", "ac_2",
              "hf_3", "ac_3", 
              "hf_4", "ac_4",
              "hf_5", "ac_5",
              "hf_6", "ac_6",
              "cs_1", "se_1",
              "cs_2", "se_2",
              "cs_3", "se_3",
              "cs_4", "se_4",
              "cs_5", "se_5",
              "cs_6", "se_6",
              "cs_7", "se_7",
              "cs_8", "se_8",
              "np_before_work",
              "np_keen_move",
              "np_city_size",
              "np_gender",
              "np_age",
              "np_education")

# rename columns with old_names and new_names vectors
df <- MyData %>% rename_at(vars(old_names1), ~ new_names1)

# filter rows with yes for Column look_job
# code needs dplyr::filter to ensure bas filter not used
df <- dplyr::filter(df, np_look_work == "yes")

# match all strings ending with job and replace with 1
# .* 
df <- df %>% 
  mutate_all(funs(str_replace_all(., '.*job$', '1')))
# reorder columns
df <- df %>% select(np_id, ends_with('work'), np_before_work:np_education, starts_with('hf_'), 
                     starts_with('ac_'), starts_with('cs_'), starts_with('se_'))


# change the blanks to NA
df <- mutate_all(df, funs(na_if(.,"")))

# change wide to long
df1 <- pivot_longer(df, 
             cols = -(starts_with("np_")), 
             names_to = c(".value", "group"),
             names_sep = "_",
             values_drop_na = TRUE)

预期结果看起来像这样,其中有四列分别用于hf_com,ac_com,curr_sal和exp_sal,值列是hf_com_freq,ac_com_freq,curr_sal_freq和exp_sal_freq:

structure(list(np_id = c("81", "83", "85", "88", "1", "2"), np_look_work = c("yes", 
"yes", "yes", "yes", "yes", "yes"), np_current_work = c("no", "yes", 
"no", "no", "no", "no"), np_before_work = c("no", "NULL", "yes", 
"yes", "yes", "yes"), np_keen_move = c("yes", "yes", "no", "no", 
"no", "no"), np_city_size = c("village", "more than 500k inhabitants", 
"more than 500k inhabitants", "village", "city up to 20k inhabitants", 
"100k - 199k inhabitants"), np_gender = c("male", "female", "female", 
"male", "female", "male"), np_age = c("18 - 24 years", "18 - 24 years", 
"more than 50 years", "18 - 24 years", "31 - 40 years", "more than 50 years"
), np_education = c("secondary", "vocational", "secondary", "secondary", 
"secondary", "secondary"), hf_com = c("hf1", "hf1", "hf1", "hf1", 
"hf1", "hf1"), hf_com_freq = c("", "", "", "1", "1", "1"), ac_com = c("ac1", 
"ac1", "ac1", "ac1", "ac1", "ac1"), ac_com_freq = c("", "", "", 
"", "", "1"), curr_sal = c("cs1", "cs1", "cs1", "cs1", "cs1", 
"cs1"), curr_sal_freq = c("", "", "", "", "", ""), exp_sal = c("se1", 
"se1", "se1", "se1", "se1", "se1"), exp_sal_freq = c("", "", 
"1", "1", "", "")), row.names = c(NA, 6L), class = "data.frame")

实际结果是:

structure(list(np_id = c("83", "83", "85", "85", "88", "88"), 
    np_look_work = c("yes", "yes", "yes", "yes", "yes", "yes"
    ), np_current_work = c("yes", "yes", "no", "no", "no", "no"
    ), np_before_work = c("NULL", "NULL", "yes", "yes", "yes", 
    "yes"), np_keen_move = c("yes", "yes", "no", "no", "no", 
    "no"), np_city_size = c("more than 500k inhabitants", "more than 500k inhabitants", 
    "more than 500k inhabitants", "more than 500k inhabitants", 
    "village", "village"), np_gender = c("female", "female", 
    "female", "female", "male", "male"), np_age = c("18 - 24 years", 
    "18 - 24 years", "more than 50 years", "more than 50 years", 
    "18 - 24 years", "18 - 24 years"), np_education = c("vocational", 
    "vocational", "secondary", "secondary", "secondary", "secondary"
    ), group = c("2", "3", "1", "2", "1", "4"), hf = c("1", NA, 
    NA, "1", "1", NA), ac = c("1", NA, NA, "1", NA, NA), cs = c("1", 
    NA, NA, "1", NA, "1"), se = c(NA, "1", "1", NA, "1", NA)), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -6L))

我可以看到的问题是,根据需要,组列不能告诉我它是hfaccs还是se

1 个答案:

答案 0 :(得分:0)

我找到了我问题的答案:

pivot_longer-将以'hf'和'ac'开头的宽格式列转换为单独列中的长格式

names_to参数:

.value =包含与原始列相对应的单元格值上的元数据

这些值以长格式进行透视,并添加到新列“ hf”和“ ac”中

“组”列的原始列尾(例如数字1-6)已设置为长格式

names_pattern =正则表达式参数,用于指定要分隔列名称的字符“ _”

df3 <- df %>% 
  tidyr::pivot_longer(cols = c(starts_with("hf"), starts_with("ac"), starts_with("cs"), starts_with("se")),
                      names_to = c(".value", "level"), 
                      names_pattern = "(.*)_(.*)"

  )