[英]removing rows based on two conditions from a data.table in R
我有一個帶有國家代碼和相應國家名稱的data.table
。 在某些情況下,國家未知, "OTHER"
用於表示未知代碼。 我的數據不一致,因為對於某些code
,我有country
名稱但也有一行帶有"OTHER",
例如IRLAND
或LUXEMBURG
。
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
# 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
相關聯。 兩種方法都不會修改這種觀察結果。
第一個是基於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
第二種解決方案直接在初始 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]]
然后,我們將只刪除country
為OTHER
且有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),]
由於duplicates
是data.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.