2017-05-30 119 views
0

我的數據幀是如下Grepl匹配多個條件,包括「與」和「或」條件

df <- data.frame(c("Utility grid", "Grid connection", "Grid", "", "", "Dry-cell-torch", "Solar", ""), c("solar", "", "", "", "", "", "Dry-cell-torch", ""), c("", "fan", "TV", "", "Utility grid connection", "", "", "Unreachable"), c("", "radio", "", "", "", "", "", "")) 
colnames(df) <- c(paste("de_", 1:4, sep="")) 

我想追加一個第5列「德」這個數據框具備以下條件 -

  • 條件1,如果所有的行是空的,例如4行中,「去」應該是0。

  • 條件2.如果只有4行的非空,並且該值可以是「包含' 「G RID」而不區分大小寫,或者是‘不可到達’,或者是‘幹細胞火炬’,然後‘的’應該是0。

  • 條件3否則‘的’應爲1

期望的「德」應該是

df$de <- (c(1, 1, 1, 0, 0, 0, 1, 0)) 

請注意我的原數據幀是600行,45列。我只是把一個子集放在這裏,但這個子集說明了我想完成的詳盡條件。

所以我試着用grepl以下的正則表達式(改編自你這裏一個不同但類似的問題在計算器給出解決辦法) -

df$de <- (!grepl("grid|Unreachable|Dry-cell-torch|^$", 
        apply(df,1,paste, collapse=""), ignore.case=TRUE))+0L 

這個工程除了在情況下,讓我們在說第1行,其中1列中有「公用事業網格」,第二個中我有「太陽能」,它使我得到0,而我需要1.我瞭解問題 - 如果網格,無法訪問等是一個目前這應該與一個'和'條件的所有其他單元格在同一行應該是空白,但我無法計算如何實現此

我感謝您的幫助!

+0

你說很多行而不是列,你能清理你的問題嗎? –

+1

如果您正在檢查4列中的任何一列是否有值,然後檢查值是否爲「無法到達」或「幹細胞火炬」,則我對您在查找條件2時感到困惑。或包含「網格」。然後每個德值將爲0爲您的示例。 –

+0

穆迪,那是因爲我的意圖是行而不是列。所以我希望R代碼遍歷4列中的每一行,並檢查列出的3個條件,並相應地爲de賦值。馬特在條件2中,如果任何列是「無法到達」或「幹細胞炬」或包含「網格」,並且如果列除了這些值之外還有非空值,則de應該是1 else應該是0. – user3816784

回答

1

考慮明確分裂的條件:

f <- function(x) { 
    if (all(x == '')) 0 
    else if (sum(x != '') == 1) { 
    if (grepl('grid', tolower(x[x != ''])) | 
     (x[x != ''] %in% c('Unreachable', 'Dry-cell-torch'))) 0 
    else 1 
    } 
    else 1 
} 

然後使用申請apply(df, 1, f)

我似乎得到你想要的載體:

> apply(df, 1, f) 
[1] 1 1 1 0 0 0 1 0 

更新:

另一個參數可用於索引f中想要的特定列。請注意,這不是一個強大的實現 - 設置錯誤的列將會破壞它。

f <- function(x, columns) { 

    y <- x[columns] 

    if (all(y == '')) 0 
    else if (sum(y != '') == 1) { 
    if (grepl('grid', tolower(y[y != ''])) | 
     (y[y != ''] %in% c('Unreachable', 'Dry-cell-torch'))) 0 
    else 1 
    } 
    else 1 
} 

然後用apply apply(df, 1, f, columns = 1:4)。只需用您想要的列替換1:4。

更新2:

不知道如果我完全理解你的最新評論,但如果你要考慮多於一個「特殊」的細胞,可以考慮以下結構(雖然我不知道如果它會比您嘗試過的更「優雅」):

f <- function(x, columns) { 

    y <- x[columns] 

    n.not.blank <- sum(y != '') 
    special <- c('Unreachable', 'Dry-cell-torch') 
    n.special <- sum(grepl('grid', tolower(y)) | (y %in% special)) 

    if (n.not.blank == 0) 0 
    else if (n.not.blank == n.special) 0 
    else 1 

} 

然後按照以前那樣使用apply。

+0

謝謝Ssokolen!這是一個很好的解決方案。我的數據框是45列和600行。按照列的順序,所討論的4列是列33:36。這個解決方案可以適應列的一個子集嗎? – user3816784

+1

@ user3816784當然,有幾種方法可以做到這一點。你可以簡單地從函數內索引x或者添加一個新的參數來以更一般的方式來完成它。我將修改我的答案。 – ssokolen

+0

謝謝ssokolen!我感謝你給編輯的答案。代碼工作正常,除了在一個場景中 - 其中兩列非空,一個讓我們說包含「網格」,另一個是「無法訪問」,其他是空白的。爲了使de爲1,我至少需要一個不包含網格的非空白列,並且不能無法達到並且乾電池割炬。我可以通過爲每列寫幾個if else語句來做到這一點,但想知道是否有更優雅的解決方案。謝謝! – user3816784

1

這應該工作。我設置了一個默認值1,然後將該值設置爲零,如果只有空白,或者只有一個空白,並且此異常值適合您的正則表達式。

df <- data.frame(c("Utility grid", "Grid connection", "Grid", "", "", "Dry-cell-torch", "Solar", ""), c("solar", "", "", "", "", "", "Dry-cell-torch", ""), c("", "fan", "TV", "", "Utility grid connection", "", "", "Unreachable"), c("", "radio", "", "", "", "", "", "")) 
colnames(df) <- c(paste("de_", 1:4, sep="")) 
df$de <- 1 # default value 
blank_rows <- apply(df,1,function(row){sum(row == "")==ncol(df)-1}) 
regex_rows <- apply(df,1,function(row){sum(row == "")==ncol(df)-2 & any(grepl("grid|Unreachable|Dry-cell-torch|^$", row,ignore.case = TRUE))}) 
df$de[blank_rows | regex_rows] <- 0 

# de_1   de_2     de_3 de_4 de 
# 1 Utility grid   solar        1 
# 2 Grid connection         fan radio 1 
# 3   Grid          TV  1 
# 4                0 
# 5        Utility grid connection  0 
# 6 Dry-cell-torch            0 
# 7   Solar Dry-cell-torch        1 
# 8           Unreachable  0 
+0

謝謝!這真的起作用,我可以看到它有助於打破不同代碼行中的條件。我想慢慢理解blank_rows和regex_rows的代碼,並且有以下問題(我仍然是初學者!)。 Q1 - 你在apply中指定了一個函數,但是你沒有在任何地方調用這個函數?它是如何工作的。 – user3816784

+0

Q2 - 在過去的代碼「sum(row ==」「)== ncol(df)-1」上你正在分配一個對象的LHS,但是這個對象也在執行一個操作,怎麼樣?我的意思是,LHS上的對象只接受右邊的操作,在「< - 」的兩邊如何同時發生操作。問題3 - 你能否爲我分解regex_rows的代碼。感謝您的幫助 - 併爲我的初學者提問,如問題 – user3816784

+0

apply的2個第一個參數意味着我們將採用df的每一行,並將它作爲參數傳遞給您放入第三個參數的函數。你可以使用一個基本函數,例如sum或者你在其他地方定義的函數,或者像我這裏所做的那樣,你可以在現場定義一個新函數 –