Задайте имена столбцов на основе других/предыдущих имен столбцов, возможно, с помощью функции apply() или цикла for

#r #for-loop #dplyr #apply

Вопрос:

У меня есть большой набор данных, где каждые 5 столбцов соответствуют измерениям 1 артерии, но назван только первый из пяти столбцов. Пример:

 
df <- structure(list("agatston", "area", "volume", "density", "mass", 
                     "agatston", "area", "volume", "density", "mass", "agatston", 
                     "area", "volume", "density", "mass"), 
                .Names = c("Artery_1", NA, NA, NA, NA, "Artery_2", NA, NA, NA, NA, "Artery_3", NA, NA, NA, NA), 
                row.names = c(NA, -1L), 
                class = c("tbl_df", "tbl", "data.frame"))
 

Что выглядит примерно так:

 df

# A tibble: 1 x 15
  Artery_1 ``    ``     ``      ``    Artery_2 ``    ``     ``      ``    Artery_3 ``    ``     ``      ``   
  <chr>    <chr> <chr>  <chr>   <chr> <chr>    <chr> <chr>  <chr>   <chr> <chr>    <chr> <chr>  <chr>   <chr>
1 agatston area  volume density mass  agatston area  volume density mass  agatston area  volume density mass 

 

Я пытаюсь использовать цикл for или применить (), чтобы имена отсутствующих столбцов были заполнены самым последним именем столбца, не отсутствующим. То, чего я пытаюсь достичь, выглядит так:

 # A tibble: 1 x 15
  Artery_1 Artery_1 Artery_1 Artery_1 Artery_1 Artery_2 Artery_2 Artery_2 Artery_2 Artery_2 Artery_3 Artery_3 Artery_3 Artery_3 Artery_3
  <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>   
1 agatston area     volume   density  mass     agatston area     volume   density  mass     agatston area     volume   density  mass 
 

Какая-нибудь помощь?

Изменить: В качестве следующего шага я хотел бы сделать столбец не_уникальным, объединив их с именем строки под ним, что приведет к следующему выводу:

  # A tibble: 1 x 15
  Artery_1_agatson Artery_1_area Artery_1_volume Artery_1_density Artery_1_mass Artery_2_agatson Artery_2_area Artery_2_volume
  <chr>            <chr>         <chr>           <chr>            <chr>         <chr>            <chr>         <chr>          
1 agatston         area          volume          density          mass          agatston         area          volume         
# ... with 7 more variables: Artery_2_density <chr>, Artery_2_mass <chr>, Artery_3_agatson <chr>, Artery_3_area <chr>,
#   Artery_3_volume <chr>, Artery_3_density <chr>, Artery_3_mass <chr>
 

Ответ №1:

Вы можете использовать zoo::na.locf для замены NA значений.

 names(df) <- zoo::na.locf(names(df))
names(df)

# [1] "Artery_1" "Artery_1" "Artery_1" "Artery_1" "Artery_1" "Artery_2"
# [7] "Artery_2" "Artery_2" "Artery_2" "Artery_2" "Artery_3" "Artery_3"
#[13] "Artery_3" "Artery_3" "Artery_3"```
 

Однако не рекомендуется использовать одно и то же имя столбца, поэтому вы можете использовать make.unique его для создания уникальных имен столбцов.

 names(df) <- make.unique(zoo::na.locf(names(df)))
names(df)

# [1] "Artery_1"   "Artery_1.1" "Artery_1.2" "Artery_1.3" "Artery_1.4"
# [6] "Artery_2"   "Artery_2.1" "Artery_2.2" "Artery_2.3" "Artery_2.4"
#[11] "Artery_3"   "Artery_3.1" "Artery_3.2" "Artery_3.3" "Artery_3.4"
 

Чтобы объединить столбцы с первой строкой, мы можем использовать

 names(df) <- paste(zoo::na.locf(names(df)), df[1, ], sep = '_')
names(df)

# [1] "Artery_1_agatston" "Artery_1_area"     "Artery_1_volume"  
# [4] "Artery_1_density"  "Artery_1_mass"     "Artery_2_agatston"
# [7] "Artery_2_area"     "Artery_2_volume"   "Artery_2_density" 
#[10] "Artery_2_mass"     "Artery_3_agatston" "Artery_3_area"    
#[13] "Artery_3_volume"   "Artery_3_density"  "Artery_3_mass"    
 

Тогда, возможно, отбросьте 1-ю строку с помощью df <- df[-1, ] .

Комментарии:

1. Спасибо вам за ваш ответ. Чтобы решить проблему с неуникальными именами столбцов: следующим шагом будет сделать их уникальными, объединив их со строкой в строке ниже. Знаете ли вы также, как этого добиться?

2. Я добавил к своему первоначальному вопросу, чтобы было более ясно, чего я пытаюсь достичь.

3. обновленный ответ должен помочь вам в этом.

Ответ №2:

Базовое решение R:

 names(df) <- paste(
  na.omit(names(df))[cumsum(!(is.na(names(df))))],
  df[1,,drop=TRUE],
  sep = "_"
)
 

ИЛИ отбросить первый ряд:

 clean_df <- setNames(
  df[-1,],
  paste(
    na.omit(names(df))[cumsum(!(is.na(names(df))))],
    df[1,,drop=TRUE],
    sep = "_"
  )
)