簡體   English   中英

根據兩個條件從 R 中的 data.table 中刪除行

[英]removing rows based on two conditions from a data.table in R

我有一個帶有國家代碼和相應國家名稱的data.table 在某些情況下,國家未知, "OTHER"用於表示未知代碼。 我的數據不一致,因為對於某些code ,我有country名稱但也有一行帶有"OTHER",例如IRLANDLUXEMBURG

code <- c(104, 105, 105, 106, 109, 112, 115, 115)
country <- c("GERMANY", "IRLAND", "OTHER", "FRANCE", "FRANCE", "ITALY",  "OTHER", "LUXEMBURG")
id_country <- cbind(code, country)
id_country <- as.data.table(id_country)

我想要做什么:我想獲得唯一的code - 對於每個代碼,只有一行,理想情況下帶有國家名稱,如果不可用,則使用“其他”。 我正在尋找最簡單的解決方案。

現在我想首先檢查我的data.table是否有一些不一致的地方。 如果是,則刪除所有在country列中同時具有 -country name 和 "OTHER" 的行。 我嘗試了以下方法,但沒有一個duplicates被刪除

if (length(unique(id_country$code)) != length(unique(id_country))){

  # replace "OTHER" with the corresponding country name 
  duplicates <- id_country[duplicated(code),]
  id_country <- id_country[!(id_country$code %in% duplicates & id_country$country == "OTHER"),]

}

所需的 output:

code <- c(104, 105, 106, 109, 112, 115)
country <- c("GERMANY", "IRLAND", "FRANCE", "FRANCE", "ITALY", "LUXEMBURG")
id_country <- cbind(code, country)
id_country <- as.data.table(id_country)

如果您願意使用dplyr ,這是另一種選擇:

code_n計算code中的重復次數, ifelse有條件地填充country變量,同時將任何“其他”條目替換為NaN以表示重復code NaN條目稍后會被過濾掉。 如果有一個帶有“OTHER”作為國家過濾的唯一代碼條目,該代碼也可以工作。=“OTHER”在這種情況下不起作用。

id_country %>% group_by (code) %>% mutate(code_n=n()) %>% mutate(country = ifelse(code_n == 1,country,ifelse(country!="OTHER",country,NaN))) %>% filter(country!=NaN) %>% select(-code_n)

Output

小標題:6 x 2

# Groups:   code [6]
  code  country  
  <chr> <chr>    
1 104   GERMANY  
2 105   IRLAND   
3 106   FRANCE   
4 109   FRANCE   
5 112   ITALY    
6 115   LUXEMBURG

我有兩個解決方案。 它們都將產生相同的結果。 如果您有大量數據,第二個可能更合適,因為它避免了合並。

在您的示例中,沒有觀察到只有一個代碼與OTHER相關聯。 兩種方法都不會修改這種觀察結果。

解決方案 1

第一個是基於merge 想法是清理僅包含代碼的data.table ,然后與初始數據合並

# METHODE 1: MERGE
id_country2 <- id_country[,.('clean_code' = unique(country)), by = code]
id_country2[, 'number_codes' := .N, by = code]
id_country2 <- id_country2[!(number_codes == 2 & clean_code == "OTHER")]

merge(id_country, id_country2)

   code number_codes   country clean_code
1:  104            1   GERMANY    GERMANY
2:  105            2    IRLAND     IRLAND
3:  105            2     OTHER     IRLAND
4:  106            1    FRANCE     FRANCE
5:  109            1    FRANCE     FRANCE
6:  112            1     ITALY      ITALY
7:  115            2     OTHER  LUXEMBURG
8:  115            2 LUXEMBURG  LUXEMBURG

解決方案 2

第二種解決方案直接在初始 dataframe 中使用條件替換。 這個想法是在執行替換之前創建一個 function,然后僅將其應用於某些代碼。

function 是:

replace_country <- function(x){
  val <- unique(x)
  return(
     gsub(pattern = "OTHER", replacement = val[val != "OTHER"][1],
          x)
) 
}

可能有更優雅的方式來定義它,但它會完成這項工作。 順便說一句,我放了val[val != "OTHER"][1]以確保您只放一個值來替換。 這可能是額外的小心,但以防萬一。

這個 function 將使用lapply + SD動詞調用

id_country[, 'number_codes' := uniqueN(country), by = "code"]
id_country[number_codes > 1,  country := lapply(.SD, replace_country), .SDcols = "country",
           by = "code"]


  code   country number_codes
1:  104   GERMANY            1
2:  105    IRLAND            2
3:  105    IRLAND            2
4:  106    FRANCE            1
5:  109    FRANCE            1
6:  112     ITALY            1
7:  115 LUXEMBURG            2
8:  115 LUXEMBURG            2

您只需使用此語法對number_codes >1 的觀察值應用replace_country function。 你的dataframe是直接引用更新的

如果希望消除具有OTHER的項目並且所有標記為OTHER的項目都是另一個國家名稱的重復項,我們可以簡單地 select 行,其中國家不等於OTHER

library(data.table)
code <- c(104, 105, 105, 106, 109, 112, 115, 115)
country <- c("GERMANY", "IRLAND", "OTHER", "FRANCE", "FRANCE", "ITALY",  "OTHER", "LUXEMBURG")
id_country <- cbind(code, country)
id_country <- as.data.table(id_country)

id_country[country != "OTHER",]

如果列表中有“有效的”未知國家(即名稱為OTHER的非重復國家代碼,則解決方案會稍微復雜一些。

首先,在使用有效的OTHER修改輸入數據后,我們將找到重復的國家/地區 117。

library(data.table)
code <- c(104, 105, 105, 106, 109, 112, 115, 115,117)
country <- c("GERMANY", "IRLAND", "OTHER", "FRANCE", "FRANCE", "ITALY",  "OTHER", 
             "LUXEMBURG","OTHER")
id_country <- cbind(code, country)
id_country <- as.data.table(id_country)
dupCodes <- id_country[, 'count' := .N, by = code][count > 1,.SD[1],by = code][[1]]

然后,我們將只刪除countryOTHER且有code重復的行。

id_country[country != "OTHER" | !(code %in% dupCodes),]

...和 output:

> id_country[country != "OTHER" | !(code %in% dupCodes),]
   code   country
1:  104   GERMANY
2:  105    IRLAND
3:  106    FRANCE
4:  109    FRANCE
5:  112     ITALY
6:  115 LUXEMBURG
7:  117     OTHER
> 

糾正原始編碼錯誤

正如最初編寫的那樣,問題帖子中的代碼包含一個微妙的錯誤,導致最終的子集操作總是失敗。

 duplicates <- id_country[duplicated(code),]

由於duplicatesdata.table ,而不是數字向量,因此以下代碼片段的計算結果始終為 FALSE。

id_country$code %in% duplicates

這段代碼在if()塊中的事實使得很難看到duplicates是一個數據表,因為我們在 RStudio 環境查看器中看不到它。 如果我在if()塊之外運行代碼塊並檢查 object,我會看到以下內容。

在此處輸入圖像描述

顯然duplicates不是向量。

此問題導致子集操作的 rest 從輸入數據表中返回每一行。

id_country <- id_country[!(id_country$code %in% duplicates & id_country$country == "OTHER"),]

為什么?

id_country$code %in% duplicates
> id_country$code %in% duplicates
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
>

我們可以通過從進行duplicates分配的代碼行中返回向量而不是數據表來糾正缺陷,如下所示。

if (length(unique(id_country$code)) != length(unique(id_country))){

     # extract first column of resulting data.table as a vector
     duplicates <- id_country[duplicated(code),][[1]]
     # subset out duplicate rows named OTHER
     id_country <- id_country[!(id_country$code %in% duplicates & id_country$country == "OTHER"),]

}
id_country

...和 output:

> id_country
   code   country
1:  104   GERMANY
2:  105    IRLAND
3:  106    FRANCE
4:  109    FRANCE
5:  112     ITALY
6:  115 LUXEMBURG
> 

我們可以使用if檢查條件:

library(data.table)

id_country[, .(country = if(any(country != 'OTHER')) 
                        country[country != 'OTHER'][1L] else 'OTHER'), code]

#   code   country
#1:  104   GERMANY
#2:  105    IRLAND
#3:  106    FRANCE
#4:  109    FRANCE
#5:  112     ITALY
#6:  115 LUXEMBURG

暫無
暫無

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

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