用 R 中最近的右侧行值填充 NA 行值
Filling NA row values with nearest right side row value in R
我想从
转换给定的数据帧
c1 c2 c3 c4 c5
VEG PUFF <NA> 12 <NA> <NA> 78.43
CHICKEN PUFF <NA> 16 <NA> 88.24 <NA>
BAKERY Total <NA> <NA> 28 <NA> 84.04
至
c1 c2
VEG PUFF 12 78.43
CHICKEN PUFF 16 88.24
BAKERY Total 28 84.04
我尝试了两种方法,但我没有得到准确的结果它有时会取左侧行值
step1 <- t(na.locf(t(df), fromLast=T))
step2 <- t(na.locf(t(step1), fromLast=F))
library(dplyr)
MyReplace = function(data) {data %>% t %>% na.locf(.,,T) %>% na.locf %>% t
我们可以使用na.omit
t(apply(df, 1, na.omit))
# [,1] [,2]
#VEG PUFF 12 78.43
#CHICKEN PUFF 16 88.24
#BAKERY Total 28 84.04
更新
根据显示的 excel 数据
lst <- apply(df, 1, na.omit)
df2 <- do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
row.names(df2) <- row.names(df)
或者另一个选项是 melt/dcast
来自 data.table
library(data.table)
dcast(melt(setDT(df1, keep.rownames=TRUE), id.var = 'rn',
na.rm = TRUE), rn~ paste0("c", rowid(rn)), value.var = "value")
# rn c1 c2 c3
#1: BAKERY Total 28 84.04 NA
#2: CHICKEN PUFF 16 88.24 143
#3: VEG PUFF 12 78.43 NA
为了提供一个可重现的例子,
df1 <- structure(list(c1 = c(NA, NA, NA), c2 = c(12L, 16L, NA), c3 = c(NA,
NA, 28L), c4 = c(NA, 88.24, NA), c5 = c(78.43, 143, 84.04)), .Names = c("c1",
"c2", "c3", "c4", "c5"), class = "data.frame", row.names = c("VEG PUFF",
"CHICKEN PUFF", "BAKERY Total"))
lst <- lapply(seq_len(nrow(df1)), function(i) {
x1 <- unlist(df1[i,])
x1[complete.cases(x1)]})
df2 <- do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
row.names(df2) <- row.names(df1)
上述方法类似于 apply
方法,除了我们可以始终确定此输出 list
(在 apply
- 它可以变化。当数字删除 NA 后元素的数量相同,它将输出 matrix
,在其他情况下输出 list
)。因此,我们遍历行序列,删除 NA
元素,在末尾填充 NA
以使 list
元素的长度相同,然后 rbind
或者另一种选择是 which
和 arr.ind=TRUE
ind <- which(!is.na(df), arr.ind=TRUE)
matrix(df[ind[order(ind[,1]),]], ncol=2, byrow=TRUE,
dimnames = list(row.names(df), paste0("c", 1:2)))
# c1 c2
#VEG PUFF 12 78.43
#CHICKEN PUFF 16 88.24
#BAKERY Total 28 84.04
更新
由于预期输出存在很多混淆,因此使用 tidyverse
解决方案
按照@DavidArenburg 的建议更新答案
library(dplyr)
library(tidyr)
df %>%
add_rownames() %>%
gather(variable, value, -rowname) %>%
filter(!is.na(value)) %>%
group_by(rowname) %>%
mutate(indx = row_number()) %>%
select(-variable) %>%
spread(indx, value)
# rowname `1` `2`
#* <chr> <dbl> <dbl>
#1 BAKERY_Total 28 84.04
#2 CHICKEN_PUFF 16 88.24
#3 VEG_PUFF 12 78.43
另一种解决方案可能是
library(data.table)
temp <- apply(df, 1, function(x) data.frame(matrix(x[!is.na(x)], nrow = 1)))
rbindlist(temp, fill = T)
上一个答案
如果我没理解错的话,您是在尝试用同一行中的最新非 NA 值替换一行中的 NA
值
我们可以使用 na.locf
并将 fromLast
设置为 TRUE
t(apply(df, 1, function(x) na.locf(x, fromLast = T, na.rm = F)))
# c1 c2 c3 c4 c5
#VEG_PUFF 12 12 78.43 78.43 78.43
#CHICKEN_PUFF 16 16 88.24 88.24 NA
#BAKERY_Total 28 28 28.00 84.04 84.04
我想从
转换给定的数据帧 c1 c2 c3 c4 c5
VEG PUFF <NA> 12 <NA> <NA> 78.43
CHICKEN PUFF <NA> 16 <NA> 88.24 <NA>
BAKERY Total <NA> <NA> 28 <NA> 84.04
至
c1 c2
VEG PUFF 12 78.43
CHICKEN PUFF 16 88.24
BAKERY Total 28 84.04
我尝试了两种方法,但我没有得到准确的结果它有时会取左侧行值
step1 <- t(na.locf(t(df), fromLast=T))
step2 <- t(na.locf(t(step1), fromLast=F))
library(dplyr)
MyReplace = function(data) {data %>% t %>% na.locf(.,,T) %>% na.locf %>% t
我们可以使用na.omit
t(apply(df, 1, na.omit))
# [,1] [,2]
#VEG PUFF 12 78.43
#CHICKEN PUFF 16 88.24
#BAKERY Total 28 84.04
更新
根据显示的 excel 数据
lst <- apply(df, 1, na.omit)
df2 <- do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
row.names(df2) <- row.names(df)
或者另一个选项是 melt/dcast
来自 data.table
library(data.table)
dcast(melt(setDT(df1, keep.rownames=TRUE), id.var = 'rn',
na.rm = TRUE), rn~ paste0("c", rowid(rn)), value.var = "value")
# rn c1 c2 c3
#1: BAKERY Total 28 84.04 NA
#2: CHICKEN PUFF 16 88.24 143
#3: VEG PUFF 12 78.43 NA
为了提供一个可重现的例子,
df1 <- structure(list(c1 = c(NA, NA, NA), c2 = c(12L, 16L, NA), c3 = c(NA,
NA, 28L), c4 = c(NA, 88.24, NA), c5 = c(78.43, 143, 84.04)), .Names = c("c1",
"c2", "c3", "c4", "c5"), class = "data.frame", row.names = c("VEG PUFF",
"CHICKEN PUFF", "BAKERY Total"))
lst <- lapply(seq_len(nrow(df1)), function(i) {
x1 <- unlist(df1[i,])
x1[complete.cases(x1)]})
df2 <- do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
row.names(df2) <- row.names(df1)
上述方法类似于 apply
方法,除了我们可以始终确定此输出 list
(在 apply
- 它可以变化。当数字删除 NA 后元素的数量相同,它将输出 matrix
,在其他情况下输出 list
)。因此,我们遍历行序列,删除 NA
元素,在末尾填充 NA
以使 list
元素的长度相同,然后 rbind
或者另一种选择是 which
和 arr.ind=TRUE
ind <- which(!is.na(df), arr.ind=TRUE)
matrix(df[ind[order(ind[,1]),]], ncol=2, byrow=TRUE,
dimnames = list(row.names(df), paste0("c", 1:2)))
# c1 c2
#VEG PUFF 12 78.43
#CHICKEN PUFF 16 88.24
#BAKERY Total 28 84.04
更新
由于预期输出存在很多混淆,因此使用 tidyverse
解决方案
library(dplyr)
library(tidyr)
df %>%
add_rownames() %>%
gather(variable, value, -rowname) %>%
filter(!is.na(value)) %>%
group_by(rowname) %>%
mutate(indx = row_number()) %>%
select(-variable) %>%
spread(indx, value)
# rowname `1` `2`
#* <chr> <dbl> <dbl>
#1 BAKERY_Total 28 84.04
#2 CHICKEN_PUFF 16 88.24
#3 VEG_PUFF 12 78.43
另一种解决方案可能是
library(data.table)
temp <- apply(df, 1, function(x) data.frame(matrix(x[!is.na(x)], nrow = 1)))
rbindlist(temp, fill = T)
上一个答案
如果我没理解错的话,您是在尝试用同一行中的最新非 NA 值替换一行中的 NA
值
我们可以使用 na.locf
并将 fromLast
设置为 TRUE
t(apply(df, 1, function(x) na.locf(x, fromLast = T, na.rm = F)))
# c1 c2 c3 c4 c5
#VEG_PUFF 12 12 78.43 78.43 78.43
#CHICKEN_PUFF 16 16 88.24 88.24 NA
#BAKERY_Total 28 28 28.00 84.04 84.04