2016-01-02 119 views
6

我的數據幀包含一些變量,其中包含像"NA"這樣的字符串缺失的值。什麼是解析數據框中包含這些數據的所有列的最有效方式,並將它們轉換爲真實的NA,這些功能可以被is.na()等功能捕獲?從「NA」字符串中解析引號

我正在使用sqldf來查詢數據庫。

重複的例子:

vect1 <- c("NA", "NA", "BANANA", "HELLO") 
vect2 <- c("NA", 1, 5, "NA") 
vect3 <- c(NA, NA, "NA", "NA") 


df = data.frame(vect1,vect2,vect3) 
+5

最好的辦法是在閱讀數據時處理這些問題。如果您正在閱讀標準工具,請查看'na.strings'參數。否則[這](http://stackoverflow.com/questions/9351089/replacing-missing-values-coded-by-in-an-r-dataframe)應該有所幫助,但用NA – user20650

+0

取代該期間被認爲是標準工具?我正在讀取一個sql數據庫中的所有數據,這可能會使得在閱讀數據時很難處理這些數據。 – jgozal

+0

沒關係,你正在使用什麼函數..很確定他們將有一個na.strings參數 – user20650

回答

5

爲了增加替代品,你也可以使用replace不是典型的blah[index] <- NA辦法。 replace會是什麼樣子:

df <- replace(df, df == "NA", NA) 

另一種選擇要考慮的是type.convert。這是R讀取數據時自動轉換列類型的功能。因此,結果與目前的方法不同,例如,第二列被轉換爲數字。

df[] <- lapply(df, function(x) type.convert(as.character(x), na.strings = "NA")) 
df 

這裏有一個性能對比。樣本數據來自@ roland的答案。

下面是功能測試:

funop <- function() { 
    df[df == "NA"] <- NA 
    df 
} 

funr <- function() { 
    ind <- which(vapply(df, function(x) class(x) %in% c("character", "factor"), FUN.VALUE = TRUE)) 
    as.data.table(df)[, names(df)[ind] := lapply(.SD, function(x) { 
    is.na(x) <- x == "NA" 
    x 
    }), .SDcols = ind][] 
} 

funam1 <- function() replace(df, df == "NA", NA) 

funam2 <- function() { 
    df[] <- lapply(df, function(x) type.convert(as.character(x), na.strings = "NA")) 
    df 
} 

這裏的標杆:

library(microbenchmark) 
microbenchmark(funop(), funr(), funam1(), funam2(), times = 10) 
# Unit: seconds 
#  expr  min  lq  mean median  uq  max neval 
# funop() 3.629832 3.750853 3.909333 3.855636 4.098086 4.248287 10 
# funr() 3.074825 3.212499 3.320430 3.279268 3.332304 3.685837 10 
# funam1() 3.714561 3.899456 4.238785 4.065496 4.280626 5.512706 10 
# funam2() 1.391315 1.455366 1.623267 1.566486 1.606694 2.253258 10 

replace將是一樣@羅蘭的做法,這是一樣的@ jgozal的。但是,type.convert方法會導致不同的列類型。

all.equal(funop(), setDF(funr())) 
all.equal(funop(), funam()) 

str(funop()) 
# 'data.frame': 10000000 obs. of 3 variables: 
# $ vect1: Factor w/ 3 levels "BANANA","HELLO",..: 2 2 NA 2 1 1 1 NA 1 1 ... 
# $ vect2: Factor w/ 3 levels "1","5","NA": NA 2 1 NA 1 NA NA 1 NA 2 ... 
# $ vect3: Factor w/ 1 level "NA": NA NA NA NA NA NA NA NA NA NA ... 

str(funam2()) 
# 'data.frame': 10000000 obs. of 3 variables: 
# $ vect1: Factor w/ 2 levels "BANANA","HELLO": 2 2 NA 2 1 1 1 NA 1 1 ... 
# $ vect2: int NA 5 1 NA 1 NA NA 1 NA 5 ... 
# $ vect3: logi NA NA NA NA NA NA ... 
4

我發現從this問題做的這個漂亮的方式:

因此,對於這種特殊的情況這純粹是:

df[df=="NA"]<-NA 

只用了與500萬行和約250變量約30秒

+0

你可以做得更快,例如使用package data.table。但是你不提供'df'的可重複的例子,這使得我無法撰寫和測試/基準測試答案。 – Roland

+0

添加了可重複的示例 – jgozal

4

這是稍快:

set.seed(42) 
df <- do.call(data.frame, lapply(df, sample, size = 1e7, replace = TRUE)) 
df2 <- df 
system.time(df[df=="NA"]<-NA) 
# user  system  elapsed 
#3.601  0.378  3.984 

library(data.table) 
setDT(df2) 
system.time({ 
    #find character and factor columns 
    ind <- which(vapply(df2, function(x) class(x) %in% c("character", "factor"), FUN.VALUE = TRUE)) 
    #assign by reference 
    df2[, names(df2)[ind] := lapply(.SD, function(x) { 
    is.na(x) <- x == "NA" 
    x 
}), .SDcols = ind] 
}) 
# user  system  elapsed 
#2.484  0.190  2.676 
all.equal(df, setDF(df2)) 
#[1] TRUE