2015-11-15 61 views
0

我試圖解決一個更大的問題,使用這個基本的例子。我需要應用基於which()的位置的函數,因爲我需要知道df1年的值,其中值爲NA或> = 150。然後,我將子集df2,得到平均值,並將其返回到確切的行。現在我正在使用一個for()循環,因爲我擁有的數據非常大,所以需要更快的速度。有沒有一種常見的方法來做到這一點?將自定義函數應用到特定的行/列

dput:

df1 <- structure(list(id = c("USC00031632", "USC00031632", "USC00031632", 
"USC00031632", "USC00031632", "USC00031632", "USC00031632", "USC00031632", 
"USC00031632", "USC00031632"), element = c("TMAX", "TMIN", "TMAX", 
"TMIN", "TMAX", "TMIN", "TMAX", "TMIN", "TMAX", "TMIN"), year = 1900:1909, 
    month = c(1, 1, 2, 2, 3, 3, 4, 4, 5, 5), day = c(1, 1, 1, 
    1, 1, 1, 1, 1, 1, 1), value = c(30.02, NA, 37.94, 10.94, 
    NA, 28.04, 64.94, 41, 200, 51.08)), .Names = c("id", "element", 
"year", "month", "day", "value"), row.names = c(NA, -10L), class = c("tbl_df", 
"data.frame")) 

df2 <-structure(list(id = c("USC00031632", "USC00031632", "USC00031632", 
"USC00031632", "USC00031632", "USC00031632", "USC00031632", "USC00031632", 
"USC00031632", "USC00031632"), element = c("TMAX", "TMIN", "TMAX", 
"TMIN", "TMAX", "TMIN", "TMAX", "TMIN", "TMAX", "TMIN"), year = 1900:1909, 
    month = c(1, 1, 2, 2, 3, 3, 4, 4, 5, 5), day = c(1, 1, 1, 
    1, 1, 1, 1, 1, 1, 1), value = c(30.02, 10.94, 37.94, 10.94, 
    12, 28.04, 64.94, 41, 82.04, 51.08)), row.names = c(NA, -10L 
), class = c("tbl_df", "data.frame"), .Names = c("id", "element", 
"year", "month", "day", "value")) 

代碼:

library(dplyr) 

check <- function(df, yr){ 
    df_d <- filter(df, year == yr) 
    m <- mean(df_d$value) 
    return(m) 
} 

for (i in which(is.na(df1$value) | df1$value >= 150)){ 
df1[i,6] <- check(df = df2, yr = as.numeric(df1[i,3])) 
} 
+0

我真的不明白,因爲'df1'和'df2'具有相同的值,只是'df2'沒有'NA's,你不能只使用'df2'來解決嗎?或者你的示例數據集非常糟糕。 –

+0

@DavidArenburg該代碼提供了我試圖解決的問題。數據集只是樣本,沒有意義。這是我追求的編程問題。 – Vedda

回答

3

我建議有效的二進制(使用:=),同時指定by = .EACHI(爲了計算從data.table與修改到位組合加入對每個組分別意味着)。

library(data.table) 
setDT(df1)[setDT(df2), 
      value := ifelse(is.na(value) | value >= 150, mean(i.value), value), 
      on = "year", 
      by = .EACHI] 
df1 
#    id element year month day value 
# 1: USC00031632 TMAX 1900  1 1 30.02 
# 2: USC00031632 TMIN 1901  1 1 10.94 
# 3: USC00031632 TMAX 1902  2 1 37.94 
# 4: USC00031632 TMIN 1903  2 1 10.94 
# 5: USC00031632 TMAX 1904  3 1 12.00 
# 6: USC00031632 TMIN 1905  3 1 28.04 
# 7: USC00031632 TMAX 1906  4 1 64.94 
# 8: USC00031632 TMIN 1907  4 1 41.00 
# 9: USC00031632 TMAX 1908  5 1 82.04 
# 10: USC00031632 TMIN 1909  5 1 51.08 

另外,我們可以如果要使用df1[, value2 := NULL]

爲了儘量避免在每一步

setDT(df1)[setDT(df2), value2 := i.value, on = "year"] 
df1[is.na(value) | value >= 150, value := mean(value2), by = year] 
df1 
#    id element year month day value value2 
# 1: USC00031632 TMAX 1900  1 1 30.02 30.02 
# 2: USC00031632 TMIN 1901  1 1 10.94 10.94 
# 3: USC00031632 TMAX 1902  2 1 37.94 37.94 
# 4: USC00031632 TMIN 1903  2 1 10.94 10.94 
# 5: USC00031632 TMAX 1904  3 1 12.00 12.00 
# 6: USC00031632 TMIN 1905  3 1 28.04 28.04 
# 7: USC00031632 TMAX 1906  4 1 64.94 64.94 
# 8: USC00031632 TMIN 1907  4 1 41.00 41.00 
# 9: USC00031632 TMAX 1908  5 1 82.04 82.04 
# 10: USC00031632 TMIN 1909  5 1 51.08 51.08 

可以擺脫value2事後ifelse開銷做這兩個步驟

+0

謝謝你的代碼,但我需要應用一個更復雜的功能,而不僅僅意味着,我也需要更多的不僅僅是知道一年;還有月份,日期和元素 – Vedda

+1

您可以在'ifelse'語句或第二個解決方案中應用* any *函數。如果你想加入更多的列,只需要花費你的'on'參數,如'on = c(「year」,「month」,「day」,「whatever」)''。 –

+0

這確實有效,但並不完全符合我的要求。我需要一種方法讓元素行傳遞給我寫的函數,以便進行計算。這似乎並不容許。在我的問題中,'check'函數使用行號:'check(df = df2,yr = as.numeric(df1 [i,3])' – Vedda