заменить NA предыдущими или последующими значениями для больших фреймов данных - PullRequest
1 голос
/ 19 июня 2020

У меня дф с 1500 набс. и более 600 переменных. В df очень много НА и я пока не нашел решения их заменить. Я бы хотел, чтобы НП приняли прежнее значение. Если предыдущего значения нет, следует выбрать следующее.

Я уже пробовал несколько решений, например na.locf et c, к сожалению, безуспешно. У меня есть решение, которое работает со средним значением. Я просто не могу его переписать так, чтобы решить мою проблему.

for (i in seq_len(ncol(df))) {
  df[is.na(df[,i]), i] <- mean(df[,i], na.rm = TRUE)
}

Может быть, кто-то здесь уже работал с этим и может мне помочь.

Вот пример:

            Share1 Share2  Share3 Share4 Share5
2016-01-04 49.5010 21.640 90.0100 93.676     NA
2016-01-05 49.7855 21.987 88.5695 92.329 82.459
2016-01-06 49.0595     NA 87.4735 88.601 81.432
2016-01-07 47.7785     NA 82.8735 83.725 78.934
2016-01-08 47.7435 20.260 82.9275 82.609 79.000
2016-01-09      NA 20.380 83.0530 83.503     NA
2016-01-10 47.7770 20.475 82.9860 83.325 79.645
2016-01-11 48.8095 20.844 83.0320 83.513 78.672
2016-01-12 48.9545     NA 83.7325 85.732 81.090
2016-01-13 48.0195 20.464 82.6305 81.151 81.178

Ответы [ 2 ]

1 голос
/ 19 июня 2020

Способ R "idiomati c" - использовать lapply, чтобы делать то, что вы просите:

df[] <- lapply(df, function(x) zoo::na.locf(zoo::na.locf(x, na.rm = FALSE), fromLast = TRUE))
df
#             Share1 Share2  Share3 Share4 Share5
# 2016-01-04 49.5010 21.640 90.0100 93.676 82.459
# 2016-01-05 49.7855 21.987 88.5695 92.329 82.459
# 2016-01-06 49.0595 21.987 87.4735 88.601 81.432
# 2016-01-07 47.7785 21.987 82.8735 83.725 78.934
# 2016-01-08 47.7435 20.260 82.9275 82.609 79.000
# 2016-01-09 47.7435 20.380 83.0530 83.503 79.000
# 2016-01-10 47.7770 20.475 82.9860 83.325 79.645
# 2016-01-11 48.8095 20.844 83.0320 83.513 78.672
# 2016-01-12 48.9545 20.844 83.7325 85.732 81.090
# 2016-01-13 48.0195 20.464 82.6305 81.151 81.178

Внутренний zoo::na.locf требует na.rm=FALSE, потому что без него Share5 будет лишен его первый элемент:

lengths(lapply(df, zoo::na.locf))
# Share1 Share2 Share3 Share4 Share5 
#     10     10     10     10      9 
lengths(lapply(df, zoo::na.locf, na.rm = FALSE))
# Share1 Share2 Share3 Share4 Share5 
#     10     10     10     10     10 

Если вам удобнее for l oop, то, возможно,

for (i in seq_along(df)) {
  df[[i]] <- zoo::na.locf(zoo::na.locf(df[[i]], na.rm = FALSE), fromLast = TRUE)
}

(Поймите, что seq_along(df) - это фактически то же самое, что и seq_len(ncol(df)).)

Как только что напомнил мне @Grothendieck, zoo:::na.locf имеет метод, который работает со всеми кадрами, поэтому приведенное выше можно уменьшить до

na.locf(na.locf(df, na.rm = FALSE), fromLast = TRUE)
0 голосов
/ 19 июня 2020

Вы также можете использовать функцию fill функцию из пакета tidyr, указав аргумент .direction как .direction = "downup". Чтобы применить функцию ко всем столбцам сразу, вы можете указать столбцы как tidy-selector everything(), который выбирает все столбцы из текущего контекста выбора.

Итак, в вашем случае это будет

df <- fill(df, everything(), .direction = "downup")

Чтобы узнать больше о функции fill, посетите this и узнайте больше о everything() function visit that .

...