#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