ฉันมีกรอบข้อมูลและบางคอลัมน์มีNA
ค่า
ฉันจะแทนที่NA
ค่าเหล่านี้ด้วยศูนย์ได้อย่างไร
ฉันมีกรอบข้อมูลและบางคอลัมน์มีNA
ค่า
ฉันจะแทนที่NA
ค่าเหล่านี้ด้วยศูนย์ได้อย่างไร
คำตอบ:
ดูความคิดเห็นของฉันในคำตอบ @ gsk3 ตัวอย่างง่ายๆ:
> m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
> d <- as.data.frame(m)
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 3 NA 3 7 6 6 10 6 5
2 9 8 9 5 10 NA 2 1 7 2
3 1 1 6 3 6 NA 1 4 1 6
4 NA 4 NA 7 10 2 NA 4 1 8
5 1 2 4 NA 2 6 2 6 7 4
6 NA 3 NA NA 10 2 1 10 8 4
7 4 4 9 10 9 8 9 4 10 NA
8 5 8 3 2 1 4 5 9 4 7
9 3 9 10 1 9 9 10 5 3 3
10 4 2 2 5 NA 9 7 2 5 5
> d[is.na(d)] <- 0
> d
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 3 0 3 7 6 6 10 6 5
2 9 8 9 5 10 0 2 1 7 2
3 1 1 6 3 6 0 1 4 1 6
4 0 4 0 7 10 2 0 4 1 8
5 1 2 4 0 2 6 2 6 7 4
6 0 3 0 0 10 2 1 10 8 4
7 4 4 9 10 9 8 9 4 10 0
8 5 8 3 2 1 4 5 9 4 7
9 3 9 10 1 9 9 10 5 3 3
10 4 2 2 5 0 9 7 2 5 5
apply
ไม่มีความจำเป็นที่จะนำไปใช้เป็น =)
แก้ไข
คุณควรดูnorm
แพ็คเกจด้วย มีคุณสมบัติที่ดีมากมายสำหรับการวิเคราะห์ข้อมูลที่ขาดหายไป =)
df[19:28][is.na(df[19:28])] <- 0
ตัวเลือกไฮบริด dplyr ตอนนี้เร็วขึ้นประมาณ 30% กว่าชุดย่อย Base R ที่กำหนดใหม่ ในดาต้าพอยต์ 100M ดาต้าพ้อยท์mutate_all(~replace(., is.na(.), 0))
รันเร็วกว่าd[is.na(d)] <- 0
ตัวเลือกพื้นฐาน R ครึ่งวินาที สิ่งที่ใครอยากจะหลีกเลี่ยงโดยเฉพาะมีการใช้หรือifelse()
if_else()
(การวิเคราะห์การทดลองทั้งหมด 600 ครั้งใช้เวลานานกว่า 4.5 ชั่วโมงส่วนใหญ่เนื่องจากรวมถึงวิธีการเหล่านี้) โปรดดูการวิเคราะห์เกณฑ์มาตรฐานด้านล่างเพื่อดูผลลัพธ์ที่สมบูรณ์
หากคุณกำลังดิ้นรนกับ dataframes ใหญ่data.table
เป็นตัวเลือกที่เร็วที่สุดของทั้งหมด: 40% เร็วกว่ามาตรฐานฐาน Rวิธี นอกจากนี้ยังแก้ไขข้อมูลในสถานที่ได้อย่างมีประสิทธิภาพช่วยให้คุณสามารถทำงานกับข้อมูลเกือบสองเท่าในครั้งเดียว
Locationally:
mutate_at(c(5:10), ~replace(., is.na(.), 0))
mutate_at(vars(var5:var10), ~replace(., is.na(.), 0))
mutate_at(vars(contains("1")), ~replace(., is.na(.), 0))
contains()
ลองends_with()
,starts_with()
mutate_at(vars(matches("\\d{2}")), ~replace(., is.na(.), 0))
เงื่อนไข:
(เปลี่ยนเพียงประเภทเดียวและปล่อยให้อยู่คนเดียวประเภทอื่น ๆ )
mutate_if(is.integer, ~replace(., is.na(.), 0))
mutate_if(is.numeric, ~replace(., is.na(.), 0))
mutate_if(is.character, ~replace(., is.na(.), 0))
อัปเดตสำหรับ dplyr 0.8.0: ฟังก์ชั่นใช้~
สัญลักษณ์รูปแบบ purrr : แทนที่funs()
อาร์กิวเมนต์ที่เลิกใช้แล้ว
# Base R:
baseR.sbst.rssgn <- function(x) { x[is.na(x)] <- 0; x }
baseR.replace <- function(x) { replace(x, is.na(x), 0) }
baseR.for <- function(x) { for(j in 1:ncol(x))
x[[j]][is.na(x[[j]])] = 0 }
# tidyverse
## dplyr
dplyr_if_else <- function(x) { mutate_all(x, ~if_else(is.na(.), 0, .)) }
dplyr_coalesce <- function(x) { mutate_all(x, ~coalesce(., 0)) }
## tidyr
tidyr_replace_na <- function(x) { replace_na(x, as.list(setNames(rep(0, 10), as.list(c(paste0("var", 1:10)))))) }
## hybrid
hybrd.ifelse <- function(x) { mutate_all(x, ~ifelse(is.na(.), 0, .)) }
hybrd.replace_na <- function(x) { mutate_all(x, ~replace_na(., 0)) }
hybrd.replace <- function(x) { mutate_all(x, ~replace(., is.na(.), 0)) }
hybrd.rplc_at.idx<- function(x) { mutate_at(x, c(1:10), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.nse<- function(x) { mutate_at(x, vars(var1:var10), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.stw<- function(x) { mutate_at(x, vars(starts_with("var")), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.ctn<- function(x) { mutate_at(x, vars(contains("var")), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.mtc<- function(x) { mutate_at(x, vars(matches("\\d+")), ~replace(., is.na(.), 0)) }
hybrd.rplc_if <- function(x) { mutate_if(x, is.numeric, ~replace(., is.na(.), 0)) }
# data.table
library(data.table)
DT.for.set.nms <- function(x) { for (j in names(x))
set(x,which(is.na(x[[j]])),j,0) }
DT.for.set.sqln <- function(x) { for (j in seq_len(ncol(x)))
set(x,which(is.na(x[[j]])),j,0) }
DT.nafill <- function(x) { nafill(df, fill=0)}
DT.setnafill <- function(x) { setnafill(df, fill=0)}
library(microbenchmark)
# 20% NA filled dataframe of 10 Million rows and 10 columns
set.seed(42) # to recreate the exact dataframe
dfN <- as.data.frame(matrix(sample(c(NA, as.numeric(1:4)), 1e7*10, replace = TRUE),
dimnames = list(NULL, paste0("var", 1:10)),
ncol = 10))
# Running 600 trials with each replacement method
# (the functions are excecuted locally - so that the original dataframe remains unmodified in all cases)
perf_results <- microbenchmark(
hybrid.ifelse = hybrid.ifelse(copy(dfN)),
dplyr_if_else = dplyr_if_else(copy(dfN)),
hybrd.replace_na = hybrd.replace_na(copy(dfN)),
baseR.sbst.rssgn = baseR.sbst.rssgn(copy(dfN)),
baseR.replace = baseR.replace(copy(dfN)),
dplyr_coalesce = dplyr_coalesce(copy(dfN)),
tidyr_replace_na = tidyr_replace_na(copy(dfN)),
hybrd.replace = hybrd.replace(copy(dfN)),
hybrd.rplc_at.ctn= hybrd.rplc_at.ctn(copy(dfN)),
hybrd.rplc_at.nse= hybrd.rplc_at.nse(copy(dfN)),
baseR.for = baseR.for(copy(dfN)),
hybrd.rplc_at.idx= hybrd.rplc_at.idx(copy(dfN)),
DT.for.set.nms = DT.for.set.nms(copy(dfN)),
DT.for.set.sqln = DT.for.set.sqln(copy(dfN)),
times = 600L
)
> print(perf_results) Unit: milliseconds expr min lq mean median uq max neval hybrd.ifelse 6171.0439 6339.7046 6425.221 6407.397 6496.992 7052.851 600 dplyr_if_else 3737.4954 3877.0983 3953.857 3946.024 4023.301 4539.428 600 hybrd.replace_na 1497.8653 1706.1119 1748.464 1745.282 1789.804 2127.166 600 baseR.sbst.rssgn 1480.5098 1686.1581 1730.006 1728.477 1772.951 2010.215 600 baseR.replace 1457.4016 1681.5583 1725.481 1722.069 1766.916 2089.627 600 dplyr_coalesce 1227.6150 1483.3520 1524.245 1519.454 1561.488 1996.859 600 tidyr_replace_na 1248.3292 1473.1707 1521.889 1520.108 1570.382 1995.768 600 hybrd.replace 913.1865 1197.3133 1233.336 1238.747 1276.141 1438.646 600 hybrd.rplc_at.ctn 916.9339 1192.9885 1224.733 1227.628 1268.644 1466.085 600 hybrd.rplc_at.nse 919.0270 1191.0541 1228.749 1228.635 1275.103 2882.040 600 baseR.for 869.3169 1180.8311 1216.958 1224.407 1264.737 1459.726 600 hybrd.rplc_at.idx 839.8915 1189.7465 1223.326 1228.329 1266.375 1565.794 600 DT.for.set.nms 761.6086 915.8166 1015.457 1001.772 1106.315 1363.044 600 DT.for.set.sqln 787.3535 918.8733 1017.812 1002.042 1122.474 1321.860 600
ggplot(perf_results, aes(x=expr, y=time/10^9)) +
geom_boxplot() +
xlab('Expression') +
ylab('Elapsed Time (Seconds)') +
scale_y_continuous(breaks = seq(0,7,1)) +
coord_flip()
qplot(y=time/10^9, data=perf_results, colour=expr) +
labs(y = "log10 Scaled Elapsed Time per Trial (secs)", x = "Trial Number") +
coord_cartesian(ylim = c(0.75, 7.5)) +
scale_y_log10(breaks=c(0.75, 0.875, 1, 1.25, 1.5, 1.75, seq(2, 7.5)))
เมื่อชุดข้อมูลขนาดใหญ่ได้รับ, Tidyr '' s replace_na
ได้ดึงอดีตออกไปข้างหน้า ด้วยการรวบรวมจุดข้อมูล 100M ปัจจุบันเพื่อให้ทำงานได้อย่างมีประสิทธิภาพเช่นเดียวกับBase R For Loop ฉันอยากรู้ว่าจะเกิดอะไรขึ้นกับดาต้าเฟรมขนาดต่าง ๆ
ตัวอย่างเพิ่มเติมสำหรับmutate
และsummarize
_at
และ_all
สายพันธุ์ที่ฟังก์ชั่นที่สามารถพบได้ที่นี่: https://rdrr.io/cran/dplyr/man/summarise_all.html
นอกจากนี้ผมพบว่าการชุมนุมประท้วงที่เป็นประโยชน์และคอลเลกชันของตัวอย่างที่นี่: https: //blog.exploratory io / dplyr-0-5-เป็นน่ากลัวริ-ทำไม-be095fd4eb8a
ขอขอบคุณเป็นพิเศษกับ:
local()
และ (ด้วยความช่วยเหลือจากผู้ป่วยของแฟรงค์ด้วย) บทบาทที่การบังคับขู่เข็ญเงียบช่วยเร่งวิธีการเหล่านี้หลายวิธี coalesce()
ฟังก์ชั่นใหม่ในและปรับปรุงการวิเคราะห์data.table
ฟังก์ชั่นที่ดีพอที่จะรวมไว้ในรายการis.numeric()
ทดสอบจริง ๆ(แน่นอนโปรดเอื้อมมือออกไปและให้พวกเขา upvotes เช่นกันหากคุณพบว่าวิธีการเหล่านั้นมีประโยชน์)
หมายเหตุเกี่ยวกับการใช้งาน Numerics ของฉัน: หากคุณมีชุดข้อมูลจำนวนเต็มจริงฟังก์ชันทั้งหมดของคุณจะทำงานได้เร็วขึ้น โปรดดูข้อมูลเพิ่มเติมจากงานของ alexiz_laz IRL ฉันจำการเผชิญหน้าชุดข้อมูลที่มีจำนวนเต็มมากกว่า 10-15% ไม่ได้ดังนั้นฉันจึงรันการทดสอบเหล่านี้กับดาต้าเฟรมที่เป็นตัวเลขอย่างสมบูรณ์
ฮาร์ดแวร์ที่ใช้ 3.9 GHz CPU พร้อม RAM 24 GB
df1[j][is.na(df1[j])] = 0
ผิดควรเป็นdf1[[j]][is.na(df1[[j]])] = 0
forLp_Sbst
ดูเหมือนจะไม่เป็นวิธีที่ทุกคนควรพิจารณาที่จะเข้าใกล้forLp_smplfSbst
coalesce()
ตัวเลือกในและรันใหม่ตลอดเวลา ขอบคุณสำหรับเขยิบที่จะอัปเดต
สำหรับเวกเตอร์เดียว:
x <- c(1,2,NA,4,5)
x[is.na(x)] <- 0
สำหรับ data.frame ให้สร้างฟังก์ชันจากด้านบนจากนั้นapply
ไปยังคอลัมน์
โปรดให้ตัวอย่างที่ทำซ้ำได้ในครั้งต่อไปตามรายละเอียดที่นี่:
is.na
เป็นฟังก์ชั่นทั่วไปและมีวิธีการสำหรับวัตถุของdata.frame
ชั้นเรียน ดังนั้นอันนี้ก็จะทำงานบนdata.frame
s!
methods(is.na)
เป็นครั้งแรกฉันเหมือนwhaaa?!? . ฉันรักเมื่อสิ่งนั้นเกิดขึ้น! =)
หากเราพยายามแทนที่NA
s เมื่อส่งออกเช่นเมื่อเขียนถึง csv เราสามารถใช้:
write.csv(data, "data.csv", na = "0")
ฉันรู้ว่าคำถามได้รับคำตอบแล้ว แต่การทำเช่นนี้อาจมีประโยชน์มากกว่าสำหรับบางคน:
กำหนดฟังก์ชั่นนี้:
na.zero <- function (x) {
x[is.na(x)] <- 0
return(x)
}
ตอนนี้เมื่อใดก็ตามที่คุณต้องการแปลง NA ในเวกเตอร์เป็นศูนย์คุณสามารถทำได้:
na.zero(some.vector)
ด้วยdplyr
0.5.0 คุณสามารถใช้coalesce
ฟังก์ชันที่สามารถรวมเข้ากับ%>%
ไปป์ไลน์ได้โดยcoalesce(vec, 0)
ง่าย สิ่งนี้จะแทนที่ NAs ทั้งหมดvec
ด้วย 0:
สมมติว่าเรามี data frame พร้อมNA
s:
library(dplyr)
df <- data.frame(v = c(1, 2, 3, NA, 5, 6, 8))
df
# v
# 1 1
# 2 2
# 3 3
# 4 NA
# 5 5
# 6 6
# 7 8
df %>% mutate(v = coalesce(v, 0))
# v
# 1 1
# 2 2
# 3 3
# 4 0
# 5 5
# 6 6
# 7 8
วิธีการทั่วไปอื่น ๆ ของการใช้replace()
ในเมทริกซ์หรือเวกเตอร์ที่จะเปลี่ยนNA
ไป0
ตัวอย่างเช่น:
> x <- c(1,2,NA,NA,1,1)
> x1 <- replace(x,is.na(x),0)
> x1
[1] 1 2 0 0 1 1
นี่เป็นอีกทางเลือกifelse()
ในการใช้งานdplyr
df = data.frame(col = c(1,2,NA,NA,1,1))
df <- df %>%
mutate(col = replace(col,is.na(col),0))
levels(A$x) <- append(levels(A$x), "notAnswered") A$x <- replace(A$x,which(is.na(A$x)),"notAnswered")
which
x1 <- replace(x,is.na(x),1)
ไม่จำเป็นต้องที่นี่คุณสามารถใช้
NA
ไป0
ในเวลาเพียงหนึ่งคอลัมน์ที่ระบุในกรอบข้อมูลขนาดใหญ่และฟังก์ชั่นนี้replace()
ทำงานได้อย่างมีประสิทธิภาพมากที่สุดในขณะนี้ยังมีส่วนใหญ่ก็
tidyr::replace_na
นอกจากนี้ยังเป็นไปได้ที่จะใช้
library(tidyr)
df <- df %>% mutate_all(funs(replace_na(.,0)))
อีกตัวอย่างหนึ่งที่ใช้แพคเกจimputeTS :
library(imputeTS)
na.replace(yourDataframe, 0)
หากคุณต้องการแทนที่ NAs ในตัวแปรปัจจัยสิ่งนี้อาจมีประโยชน์:
n <- length(levels(data.vector))+1
data.vector <- as.numeric(data.vector)
data.vector[is.na(data.vector)] <- n
data.vector <- as.factor(data.vector)
levels(data.vector) <- c("level1","level2",...,"leveln", "NAlevel")
มันจะแปลงแฟคเตอร์แบบเวกเตอร์เป็นเวกเตอร์ตัวเลขและเพิ่มอีกหนึ่งระดับตัวเลขเชิงประดิษฐ์ซึ่งจะถูกแปลงกลับไปเป็นแฟคเตอร์แบบเวกเตอร์พร้อมระดับ "NA-level" พิเศษที่คุณเลือก
จะแสดงความคิดเห็นในโพสต์ของ @ ianmunoz แต่ฉันไม่มีชื่อเสียงเพียงพอ คุณสามารถรวมdplyr
's mutate_each
และreplace
การดูแลของNA
การ0
ทดแทน กำลังใช้งาน dataframe จากคำตอบของ @ aL3xa ...
> m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
> d <- as.data.frame(m)
> d
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 8 1 9 6 9 NA 8 9 8
2 8 3 6 8 2 1 NA NA 6 3
3 6 6 3 NA 2 NA NA 5 7 7
4 10 6 1 1 7 9 1 10 3 10
5 10 6 7 10 10 3 2 5 4 6
6 2 4 1 5 7 NA NA 8 4 4
7 7 2 3 1 4 10 NA 8 7 7
8 9 5 8 10 5 3 5 8 3 2
9 9 1 8 7 6 5 NA NA 6 7
10 6 10 8 7 1 1 2 2 5 7
> d %>% mutate_each( funs_( interp( ~replace(., is.na(.),0) ) ) )
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 8 1 9 6 9 0 8 9 8
2 8 3 6 8 2 1 0 0 6 3
3 6 6 3 0 2 0 0 5 7 7
4 10 6 1 1 7 9 1 10 3 10
5 10 6 7 10 10 3 2 5 4 6
6 2 4 1 5 7 0 0 8 4 4
7 7 2 3 1 4 10 0 8 7 7
8 9 5 8 10 5 3 5 8 3 2
9 9 1 8 7 6 5 0 0 6 7
10 6 10 8 7 1 1 2 2 5 7
เรากำลังใช้การประเมินมาตรฐาน (SE) ที่นี่ซึ่งเป็นสาเหตุที่เราต้องการขีดล่างบน " funs_
" นอกจากนี้เรายังใช้lazyeval
's interp
/ ~
และ.
อ้างอิง "ทุกสิ่งที่เราทำงานด้วย" เช่นกรอบข้อมูล ตอนนี้มีศูนย์!
คุณสามารถใช้ได้ replace()
ตัวอย่างเช่น:
> x <- c(-1,0,1,0,NA,0,1,1)
> x1 <- replace(x,5,1)
> x1
[1] -1 0 1 0 1 0 1 1
> x1 <- replace(x,5,mean(x,na.rm=T))
> x1
[1] -1.00 0.00 1.00 0.00 0.29 0.00 1.00 1.00
NA
s ในเวกเตอร์ของคุณ มันดีสำหรับเวกเตอร์ตัวเล็ก ๆ ดังตัวอย่างของคุณ
x1 <- replace(x,is.na(x),1)
จะทำงานโดยไม่แสดงรายการค่าดัชนีอย่างชัดเจน
dplyr
ตัวเลือกที่เข้ากันได้กับไปป์อื่นด้วยtidyr
วิธีการreplace_na
ที่ใช้ได้กับหลายคอลัมน์:
require(dplyr)
require(tidyr)
m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
d <- as.data.frame(m)
myList <- setNames(lapply(vector("list", ncol(d)), function(x) x <- 0), names(d))
df <- d %>% replace_na(myList)
คุณสามารถ จำกัด เช่นคอลัมน์ตัวเลขได้อย่างง่ายดาย:
d$str <- c("string", NA)
myList <- myList[sapply(d, is.numeric)]
df <- d %>% replace_na(myList)
ฟังก์ชันเฉพาะ ( nafill
/ setnafill
) สำหรับจุดประสงค์นั้นอยู่ในdata.table
รุ่นล่าสุด
install.packages("data.table", repos="https://Rdatatable.gitlab.io/data.table")
library(data.table)
ans_df = nafill(df, fill=0)
setnafill(df, fill=0) # this one updates in-place
ฟังก์ชั่นที่เรียบง่ายนี้สกัดจากDatacampสามารถช่วย:
replace_missings <- function(x, replacement) {
is_miss <- is.na(x)
x[is_miss] <- replacement
message(sum(is_miss), " missings replaced by the value ", replacement)
x
}
แล้วก็
replace_missings(df, replacement = 0)
วิธีง่ายๆในการเขียนนั้นif_na
มาจากhablar
:
library(dplyr)
library(hablar)
df <- tibble(a = c(1, 2, 3, NA, 5, 6, 8))
df %>%
mutate(a = if_na(a, 0))
ซึ่งผลตอบแทน:
a
<dbl>
1 1
2 2
3 3
4 0
5 5
6 6
7 8
ในการแทนที่ NAs ทั้งหมดใน dataframe คุณสามารถใช้:
df %>% replace(is.na(.), 0)
หากคุณต้องการกำหนดชื่อใหม่หลังจากเปลี่ยน NAs ในคอลัมน์ที่ระบุในคอลัมน์กรณีนี้ V3 ให้ใช้คุณสามารถทำเช่นนี้ได้
my.data.frame$the.new.column.name <- ifelse(is.na(my.data.frame$V3),0,1)