簡體   English   中英

將值分配給R中的數據框子集

[英]asssign values to dataframe subset in R

我在將數據幀分配給另一個子集時遇到麻煩。 在下面的示例中,

ds[cavities,] <- join(ds[cavities,1:4], fillings, by="ZipCode", "left")

僅修改一列而不是兩列。 我希望它要么不修改任何列,要么不修改兩個列,而不僅僅是一個。 我通過將ds連接到另一個數據框cs編寫了函數,以填充數據CountyID dsPrefNameCountyID列(它們是NA

如您所見,如果沒有運行它,則測試將失敗,因為PrefName未被填充。在進行了一些調試之后,我意識到join()確實在執行預期的操作,但實際上是對該連接的結果PrefName NA

# fully copy-paste-run-able (but broken) code                                                    
suppressMessages({                                                          
    library("plyr")                                                         
    library("methods")                                                      
    library("testthat")                                                     
}) 

# Fill in the missing PrefName/CountyIDs in delstat                         
#   - Find the missing values in Delstat                                    
#   - Grab the CityState Primary Record values                              
#   - Match on zipcode to fill in the holes in the delstat data             
#   - Remove any codes that could not be fixed                              
#   - @param ds: delstat dataframe with 6 columns (see test case)           
#   - @param cs: citystate dataframe with 6 columns (see test case) 
getMissingCounties <- function(ds, cs) {                                    

    if (length(is.na(ds$CountyID))) {                                       

        cavities <- which(is.na(ds$CountyID))                               
        fillings <- cs[cs$PrimRec==TRUE, c(1,3,4)]                          

        ds[cavities,] <- join(ds[cavities,1:4], fillings, by="ZipCode", "left")

        ds <- ds[!is.na(ds$CountyID),]                                      
    }                                                                       

    return(ds)                                                              
}                                                                           
test_getMissingCounties <- function() {                                     

    ds <- data.frame(                                                       
        CityStateKey = c(1,     2,  3,  4  ),                               
        ZipCode      = c(11,    22, 33, 44 ),                               
        Business     = c(1,     1,  1,  1  ),                               
        Residential  = c(1,     1,  1,  1  ),                               
        PrefName     = c("One", NA , NA, NA),                               
        CountyID     = c(111,   NA,  NA, NA))                               

    cs <- data.frame(                                                       
        ZipCode      = c(11,    22,    22,    33,      55    ),             
        Name         = c("eh",  "eh?", "eh?", "eh!?",  "ah." ),             
        PrefName     = c("One", "To",  "Two", "Three", "Five"),             
        CountyID     = c(111,   222,   222,   333,     555   ),             
        PrimRec      = c(TRUE,  FALSE, TRUE,  TRUE,    TRUE  ),             
        CityStateKey = c(1,     2,     2,     3,       5     ))             

    expected <- data.frame(                                                 
        CityStateKey = c(1,     2,     3      ),                            
        ZipCode      = c(11,    22,    33     ),                            
        Business     = c(1,     1,     1      ),                            
        Residential  = c(1,     1,     1      ),                            
        PrefName     = c("One", "Two", "Three"),                            
        CountyID     = c(111,   222,   333    ))                            

    expect_equal(getMissingCounties(ds, cs), expected)                      
}

# run the test
test_getMissingCounties()

結果是:

CityStateKey ZipCode Business Residential PrefName CountyID
       1       11        1          1       One      111
       2       22        1          1      <NA>      222
       3       33        1          1      <NA>      333

有什么想法為什么PrefName會被分配設置為NA或如何進行分配,以免丟失數據?

簡短的答案是,可以通過確保數據幀中沒有任何因素來避免此問題。 您可以通過在data.frame(...)的調用中使用stringsAsFactors=FALSEdata.frame(...) 請注意,默認情況下,許多數據導入功能(包括read.table(...)read.csv(...)也會將字符轉換為因數。 您可以用相同的方法來擊敗這種行為。

這個問題實際上是非常微妙的,並且也是R在數據類型之間的“沉默強制”如何造成各種問題的一個很好的例子。

data.frame(...)函數默認將任何字符向量轉換為因子。 因此,在您的代碼中, ds$PerfName是一個具有一個級別的因子,而cs$PerfName是一個具有五個級別的因子。 因此,在您的工作分配聲明中:

ds[cavities,] <- join(ds[cavities,1:4], fillings, by="ZipCode", "left")

LHS的第5列是1級因子,RHS的第5列是5級因子。

在某些情況下 ,當您將具有較高級別的因子分配給具有較少級別的因子時,缺少的級別將設置為NA 考慮一下:

x <- c("A","B",NA,NA,NA)  # character vector          
y <- LETTERS[1:5]         # character vector
class(x); class(y)
# [1] "character"
# [1] "character"

df <- data.frame(x,y)     # x and y coerced to factor
sapply(df,class)          # df$x and df$y are factors
#        x        y 
# "factor" "factor" 

# assign rows 3:5 of col 2 to col 1
df[3:5,1] <- df[3:5,2]    # fails with a warning
# Warning message:
# In `[<-.factor`(`*tmp*`, iseq, value = 3:5) :
#   invalid factor level, NA generated
df                        # missing levels set to NA
#      x y
# 1    A A
# 2    B B
# 3 <NA> C
# 4 <NA> D
# 5 <NA> E

上面的示例等效於您的賦值語句。 但是,請注意如果將第2列的全部分配給第1列會發生什么。

# assign all of col 2 to col 1
df <- data.frame(x,y)
df[,1] <- df[,2]          # succeeds!!
df
#   x y
# 1 A A
# 2 B B
# 3 C C
# 4 D D
# 5 E E

這可行。

最后,關於調試的說明:如果要調試函數,有時在命令行 (例如,在全局環境中)逐行運行語句會很有用。 如果這樣做,您將得到上面的警告,而在函數調用中,警告被抑制。

可以通過以下方式重新實現getMissingCountries來滿足測試的約束:

merge(ds[1:4], subset(subset(cs, PrimRec)[c(1, 3, 4)]), by="ZipCode")

注意:總是首先發出ZipCode列,這與您的預期結果不同。

但是要回答子分配問題:它會中斷,因為PrefName的級別集在dscs之間不兼容。 避免使用因素或重新relevel它們。 您可能已經錯過了R對此的警告,因為test那以某種方式抑制了警告。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM