簡體   English   中英

根據R中另一個數據框的值有條件地將1或0分配給新列

[英]Assigning 1 or 0 conditionally to a new column based on values from another dataframe in R

我有一個32,000個條目的data.frame 這是一個示例:

# df1
MINEVENT MAXEVENT      EVENTRANGE NUMEVENT cplt_flag
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0
 2680001  2680051 2680001-2680051       51         0

另一個帶有157個值的列表。 這是一個示例:

# df2
source_id
   211535
   211535
   211535
   211536
   211536
   211536

我想從source_id讀取並測試該值是否介於MINEVENTMAXEVENT之間。 如果為TRUE則我想在cplt_flag輸入值1 ,否則為0

我有一個使用if-else語句的代碼,但對於32,000個條目,它的運行速度非常慢。 另外,我一直在嘗試使用函數和應用函數,但是無法使其正常工作。

我正在尋找一種有效的方法來完成此任務。

您的數據集實際上並沒有任何可能會出現TRUE情況的情況。但是,這是一個使用data.table v1.9.7當前開發版本中新的非等額聯接功能的解決方案。 請參閱此處的安裝說明。

require(data.table) #v1.9.7+

setDT(df2)
setDT(df1)[df2, cplt_flag := 1, on = .(MINEVENT <= source_id, MAXEVENT >= source_id)]

對於df2每一行,在滿足提供給on=參數的條件的情況下,從df1中提取匹配的行索引。 在這些行索引上, cplt_flag 更新1

使用match.criterion函數和apply函數之一的替代解決方案,該解決方案應比循環更快。 我添加了一些額外的數據行進行測試(不是窮舉,而是說明性的):

df1 <- read.table(text = "
                  MINEVENT MAXEVENT      EVENTRANGE NUMEVENT cplt_flag
                  211535   211634  211535-211634        100         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680001  2680051 2680001-2680051       51         0
                  2680101  2680151 2680101-2680151       51         0", header = TRUE)

df2 <- read.table(text = "
                  source_id
                  211535
                  211535
                  211535
                  211536
                  211536
                  211536
                  2680051", header = TRUE)

match.criterion <- function(source.id, df1) {
  matches <- which(df1$MINEVENT <= source.id & source.id <= df1$MAXEVENT)
  df1$cplt_flag[matches] <<- 1
}

sapply(df2$source_id, match.criterion, df1 = df1)
print(df1)
##  MINEVENT MAXEVENT      EVENTRANGE NUMEVENT cplt_flag
##1   211535   211634   211535-211634      100         1
##2  2680001  2680051 2680001-2680051       51         1
##3  2680001  2680051 2680001-2680051       51         1
##4  2680001  2680051 2680001-2680051       51         1
##5  2680001  2680051 2680001-2680051       51         1
##6  2680001  2680051 2680001-2680051       51         1
##7  2680001  2680051 2680001-2680051       51         1
##8  2680101  2680151 2680101-2680151       51         0

筆記:

  1. 這里的關鍵是了解R的作用域規則 要在函數范圍之外修改變量,請使用<<-代替<- 請參閱以獲取解釋,並注意有關使用<<-的警告。

  2. 假設df1$cplt_flag最初為全零,因為match.criterion僅將匹配的行設置為1 也就是說,與source_id每個值的標准都不匹配的df1行將被保留。

使用foreach而不是apply函數之一的另一個矢量化解決方案是:

require(foreach)
foreach(source.id = df2$source_id) %do% match.criterion(source.id, df1)

暫無
暫無

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

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