Saya memiliki bingkai data dan beberapa kolom memiliki NA
nilai.
Bagaimana cara mengganti NA
nilai - nilai ini dengan nol?
Saya memiliki bingkai data dan beberapa kolom memiliki NA
nilai.
Bagaimana cara mengganti NA
nilai - nilai ini dengan nol?
Jawaban:
Lihat komentar saya di jawaban @ gsk3. Contoh sederhana:
> 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
Tidak perlu mendaftar apply
. =)
EDIT
Anda juga harus melihat pada norm
paket. Ini memiliki banyak fitur bagus untuk analisis data yang hilang. =)
df[19:28][is.na(df[19:28])] <- 0
Opsi dplyr hibridisasi sekarang sekitar 30% lebih cepat daripada yang ditetapkan oleh subset Base R. Pada kerangka data 100M datapoint mutate_all(~replace(., is.na(.), 0))
berjalan setengah detik lebih cepat dari d[is.na(d)] <- 0
opsi R dasar . Apa yang ingin dihindari seseorang secara khusus adalah menggunakan ifelse()
atau if_else()
. (Analisis uji coba lengkap 600 berjalan lebih dari 4,5 jam sebagian besar karena termasuk pendekatan ini.) Silakan lihat analisis benchmark di bawah ini untuk hasil lengkap.
Jika Anda kesulitan dengan kerangka data yang besar, data.table
adalah opsi tercepat: 40% lebih cepat daripada pendekatan Basis R standar . Ini juga memodifikasi data di tempat, secara efektif memungkinkan Anda untuk bekerja dengan data yang hampir dua kali lipat sekaligus.
Berlokasi:
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()
, coba ends_with()
,starts_with()
mutate_at(vars(matches("\\d{2}")), ~replace(., is.na(.), 0))
Persyaratan:
(ganti hanya tipe tunggal dan biarkan tipe lainnya saja.)
mutate_if(is.integer, ~replace(., is.na(.), 0))
mutate_if(is.numeric, ~replace(., is.na(.), 0))
mutate_if(is.character, ~replace(., is.na(.), 0))
Diperbarui untuk dplyr 0.8.0: fungsi menggunakan ~
simbol format purrr : mengganti funs()
argumen yang sudah usang .
# 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)))
Ketika dataset bertambah besar, Tidyr 's replace_na
secara historis menarik di depan. Dengan pengumpulan poin data 100M saat ini untuk dijalankan, ia melakukan hampir persis serta Base R For Loop. Saya ingin tahu apa yang terjadi untuk berbagai dataframe ukuran.
Contoh tambahan untuk mutate
dan summarize
_at
dan _all
varian fungsi dapat ditemukan di sini: https://rdrr.io/cran/dplyr/man/summarise_all.html
Selain itu, saya menemukan demonstrasi dan koleksi contoh yang membantu di sini: https: //blog.exploratory. io / dplyr-0-5-is-awesome-heres-why-be095fd4eb8a
Dengan terima kasih khusus kepada:
local()
, dan (dengan bantuan Frank, juga) peran yang dimainkan oleh pemaksaan bisu dalam mempercepat banyak pendekatan ini. coalesce()
fungsi yang dan memperbarui analisis.data.table
fungsi cukup baik untuk akhirnya memasukkannya ke dalam lineup.is.numeric()
sebenarnya diuji.(Tentu saja, tolong jangkau dan beri mereka upvotes, juga jika Anda menganggap pendekatan itu berguna.)
Catatan tentang penggunaan Numerik: Jika Anda memiliki dataset integer murni, semua fungsi Anda akan berjalan lebih cepat. Silakan lihat pekerjaan alexiz_laz untuk informasi lebih lanjut. IRL, saya tidak dapat mengingat menemukan kumpulan data yang mengandung lebih dari 10-15% bilangan bulat, jadi saya menjalankan tes ini pada kerangka data numerik sepenuhnya.
Perangkat Keras Menggunakan CPU 3,9 GHz dengan RAM 24 GB
df1[j][is.na(df1[j])] = 0
salah, seharusnyadf1[[j]][is.na(df1[[j]])] = 0
forLp_Sbst
sepertinya tidak ada cara orang harus mempertimbangkan untuk mendekati vsforLp_smplfSbst
coalesce()
opsi dan jalankan kembali setiap saat. Terima kasih atas dorongan untuk memperbarui.
Untuk satu vektor:
x <- c(1,2,NA,4,5)
x[is.na(x)] <- 0
Untuk data.frame, buat fungsi dari yang di atas, lalu apply
ke kolom.
Harap berikan contoh yang dapat direproduksi lain kali seperti yang dijelaskan di sini:
Bagaimana cara membuat contoh R yang hebat yang bisa direproduksi?
is.na
adalah fungsi generik, dan memiliki metode untuk objek data.frame
kelas. jadi ini juga akan bekerja pada data.frame
s!
methods(is.na)
untuk pertama kalinya, saya seperti whaaa?!? . Saya suka ketika hal-hal seperti itu terjadi! =)
contoh dplyr:
library(dplyr)
df1 <- df1 %>%
mutate(myCol1 = if_else(is.na(myCol1), 0, myCol1))
Catatan: Ini karya per kolom yang dipilih, jika kita perlu melakukan ini untuk semua kolom, lihat @reidjax 's jawaban menggunakan mutate_each .
Saya tahu pertanyaannya sudah dijawab, tetapi melakukannya dengan cara ini mungkin lebih bermanfaat bagi beberapa orang:
Tentukan fungsi ini:
na.zero <- function (x) {
x[is.na(x)] <- 0
return(x)
}
Sekarang, setiap kali Anda perlu mengonversi NA dalam vektor menjadi nol, Anda dapat melakukannya:
na.zero(some.vector)
Dengan dplyr
0.5.0, Anda dapat menggunakan coalesce
fungsi yang dapat dengan mudah diintegrasikan ke dalam %>%
pipeline dengan melakukan coalesce(vec, 0)
. Ini menggantikan semua NAS vec
dengan 0:
Katakanlah kita memiliki bingkai data dengan 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
Pendekatan yang lebih umum menggunakan replace()
dalam matriks atau vektor untuk menggantikan NA
untuk0
Sebagai contoh:
> x <- c(1,2,NA,NA,1,1)
> x1 <- replace(x,is.na(x),0)
> x1
[1] 1 2 0 0 1 1
Ini juga merupakan alternatif untuk menggunakan ifelse()
didplyr
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
tidak diperlukan di sini, Anda dapat menggunakannya x1 <- replace(x,is.na(x),1)
.
NA
untuk 0
hanya dalam satu kolom tertentu dalam bingkai data yang besar dan fungsi ini replace()
bekerja paling efektif sementara juga paling sederhana.
Jika Anda ingin mengganti NAS dalam variabel faktor, ini mungkin berguna:
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")
Ini mengubah vektor faktor menjadi vektor numerik dan menambahkan tingkat faktor numerik artifis lain, yang kemudian diubah kembali ke vektor faktor dengan satu "tingkat NA" tambahan pilihan Anda.
Akan mengomentari pos @ ianmunoz tetapi saya tidak memiliki reputasi yang cukup. Anda dapat menggabungkan dplyr
's mutate_each
dan replace
untuk mengurus NA
untuk 0
pengganti. Menggunakan dataframe dari jawaban @ 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
Kami menggunakan evaluasi standar (SE) di sini yang mengapa kami membutuhkan garis bawah pada " funs_
." Kami juga menggunakan lazyeval
's interp
/ ~
dan .
referensi 'segala sesuatu yang kita bekerja dengan', yaitu frame data. Sekarang ada nol!
Kamu bisa menggunakan replace()
Sebagai contoh:
> 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 di vektor Anda. Baik untuk vektor kecil seperti pada contoh Anda.
x1 <- replace(x,is.na(x),1)
akan berfungsi tanpa mencantumkan nilai indeks secara eksplisit.
dplyr
Opsi lain yang kompatibel dengan pipa dengan tidyr
metode replace_na
yang berfungsi untuk beberapa kolom:
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)
Anda dapat dengan mudah membatasi misalnya kolom angka:
d$str <- c("string", NA)
myList <- myList[sapply(d, is.numeric)]
df <- d %>% replace_na(myList)
Fungsi khusus ( nafill
/ setnafill
) untuk tujuan itu ada dalam data.table
versi terbaru
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
Untuk mengganti semua NAS dalam kerangka data yang dapat Anda gunakan:
df %>% replace(is.na(.), 0)
jika Anda ingin menetapkan nama baru setelah mengubah NAS dalam kolom tertentu dalam kolom kasus ini V3, gunakan Anda juga dapat melakukannya seperti ini
my.data.frame$the.new.column.name <- ifelse(is.na(my.data.frame$V3),0,1)