Таблица R имеет значения только при изменении способа получения всех значений без цикла for

#r #for-loop

#r #для цикла

Вопрос:

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

Единственный способ, который я нашел для решения этой проблемы, — использовать цикл for и проверять наличие пустого значения и ссылаться на значение из предыдущей строки.

Пример таблицы

    Col.a Col.b Col.c Col.d Col.e Col.f
1     XX  XXXX  BBBB  CCCC  DDDD     1
2      Â     Â     Â     Â     Â     Â
3     YY  YYYY  BBBB  DDDD  FFFF     1
4      Â     Â  CCCC  EEEE   GGG     2
5     VV  VVVV     Â     Â     Â     3
6      Â     Â     Â     Â     Â     Â
7     CC   CCC  CCC1  DDDD  DDDD     1
8      Â     Â  CCC2  EEEE  EEEE     1
9      Â     Â  CCC3  1111  1123     3
10    CC   CCC     Â     Â     Â     5
11     Â     Â     Â     Â     Â     Â
 

Пример кода для создания фрейма данных, удаления пустых / промежуточных строк и замены значений предыдущими для столбцов 1-2

 dftest <- 
  structure(list(Col.a = c("XX", "Â", "YY", "Â", "VV", "Â", "CC", 
  "Â", "Â", "CC", "Â"), Col.b = c("XXXX", "Â", "YYYY", "Â", "VVVV", 
  "Â", "CCC", "Â", "Â", "CCC", "Â"), Col.c = c("BBBB", "Â", "BBBB", 
  "CCCC", "Â", "Â", "CCC1", "CCC2", "CCC3", "Â", "Â"), Col.d = c("CCCC", 
  "Â", "DDDD", "EEEE", "Â", "Â", "DDDD", "EEEE", "1111", "Â", "Â"
  ), Col.e = c("DDDD", "Â", "FFFF", "GGG", "Â", "Â", "DDDD", "EEEE", 
  "1123", "Â", "Â"), Col.f = c("1", "Â", "1", "2", "3", "Â", "1", 
  "1", "3", "5", "Â")), class = "data.frame", row.names = c(NA, 
  -11L))


#drop "Â" in col.c as only reason is empty row or subtotal row which is not needed
dftest <- dftest[!dftest$Col.c == "Â",]

for (i in 1:nrow(dftest)) {
  if (dftest$Col.a[i] == "Â") {
      dftest$Col.a[i] = dftest$Col.a[i-1]
  }
  if (dftest$Col.b[i] == "Â") {
    dftest$Col.b[i] = dftest$Col.b[i-1]
  }
}
 

Вывод из приведенного выше кода — это то, что я хочу, можно ли это сделать без цикла for, поскольку некоторые таблицы большие, и их много.

   Col.a Col.b Col.c Col.d Col.e Col.f
1    XX  XXXX  BBBB  CCCC  DDDD     1
3    YY  YYYY  BBBB  DDDD  FFFF     1
4    YY  YYYY  CCCC  EEEE   GGG     2
7    CC   CCC  CCC1  DDDD  DDDD     1
8    CC   CCC  CCC2  EEEE  EEEE     1
9    CC   CCC  CCC3  1111  1123     3
 

Ответ №1:

Мы могли бы использовать case_when для каждого столбца отдельно, а затем выполнить filter

 library(dplyr)
dftest %>%
   mutate(across(everything(), ~ case_when(. == "Â" ~ lag(.), 
           TRUE ~ .))) %>%
   distinct %>% 
   filter(across(everything(), ~ . != "Â"))
 

Ответ №2:

Вы можете использовать accumulate from purrr для рекурсивного вычисления.

 library(dplyr)
library(purrr)

dftest %>%
  filter(Col.c != 'Â') %>%
  mutate(across(c(Col.a, Col.b), 
         ~accumulate(., ~if_else(.y == 'Â', .x, .y)))) -> result

result

#  Col.a Col.b Col.c Col.d Col.e Col.f
#1    XX  XXXX  BBBB  CCCC  DDDD     1
#2    YY  YYYY  BBBB  DDDD  FFFF     1
#3    YY  YYYY  CCCC  EEEE   GGG     2
#4    CC   CCC  CCC1  DDDD  DDDD     1
#5    CC   CCC  CCC2  EEEE  EEEE     1
#6    CC   CCC  CCC3  1111  1123     3