为什么 rbind() 在 for 循环中不起作用?
Why doesn't rbind() work inside a for loop?
我有一个日期范围:
date_rng <- seq( as.Date("2008-01-01"), as.Date("2008-12-31"), by="+1 day")
我有一些与问题必然相关的辅助函数,我会尽量将它们排除在外。
我从第一个约会开始调用这个函数:
# Function for getting weather table by airport code and date and return dataframe
get_table <- function(code, date){
adv <- sprintf(
"https://www.wunderground.com/history/airport/K%s/2008/%s/%s/DailyHistory.html",
code, month(date), day(date)
)
h <- adv %>% read_html()
t <- h%>%
html_nodes(xpath = '//*[@id="obsTable"]') %>%
html_table()
df <- data.frame(t)
return(df)
}
atl_weather <- get_table("ATL", date_rng[1])
现在我遍历其余日期,为每个日期创建一个新的 df,然后我尝试将其附加到原始日期:
# Loop through remaining dates and bind dfs
for(d in as.list(date_rng[2:4])){
rbind(atl_weather, get_table("ATL", d), d)
}
但是绑定没有发生,我只剩下范围内第一个日期的原始数据框,它是在 for 循环之前创建的。
这虽然有效:
atl_weather <- get_table("ATL", date_rng[1])
new_df <- get_table("ATL", date_rng[2])
new_df <- scraped_data_formatter(new_df, date_rng[2])
rbind(atl_weather, new_df)
如何让 rbind() 在 for 循环中工作(以便我迭代构建数据框以包含完整日期范围内的所有数据)?
确实有效。问题是您丢弃了结果,因为您没有将 rbind()
的输出分配给任何东西。
改变
rbind(atl_weather, get_table("ATL", d), d)
至此
atl_weather <- rbind(atl_weather, get_table("ATL", d), d)
假设 atl_weather
是您要增量添加的数据框。
就是说,您不想在 R 中这样做;每次向对象添加 column/row 时,R 都需要进行大量数据复制。基本上,以这种方式递增增长的对象会产生大量开销,这样做肯定会让您的代码陷入困境。
理想情况下,您首先分配足够的 space(即足够的行以便您可以在分配时索引第 i
行:new_atl_weather[i, ] <- c(....)
。)
我会冒着跑题的风险(因为这个问题已经得到正确回答),只要我被迫在 for 循环中构建数据框,我就会为您提供我最喜欢的编程模式:
for (d in as.list(date_rng[2:4])){
if (exists("atl_weather")) {
atl_weather = rbind(atl_weather, get_table("ATL", d), d)
} else {
atl_weather = get_table("ATL", d)
}
}
当然,如果我有 get_table
中包含的功能,我会改用某种 apply
语句。但是当现实生活妨碍并且 for 循环的内部太复杂时,我通常会使用类似的模式将某种 temp.data.frame
对象分配给或绑定到 atl_weather
以上:
if (exists("atl_weather")) rm(atl_weather) # in case I'm dynamically running code in chunks
for (d in as.list(date_rng[2:4])){
temp.df = ... # complicated stuff
if (exists("atl_weather")) {
atl_weather = rbind(atl_weather, temp.df)
} else {
atl_weather = temp.df
}
}
我有一个日期范围:
date_rng <- seq( as.Date("2008-01-01"), as.Date("2008-12-31"), by="+1 day")
我有一些与问题必然相关的辅助函数,我会尽量将它们排除在外。
我从第一个约会开始调用这个函数:
# Function for getting weather table by airport code and date and return dataframe
get_table <- function(code, date){
adv <- sprintf(
"https://www.wunderground.com/history/airport/K%s/2008/%s/%s/DailyHistory.html",
code, month(date), day(date)
)
h <- adv %>% read_html()
t <- h%>%
html_nodes(xpath = '//*[@id="obsTable"]') %>%
html_table()
df <- data.frame(t)
return(df)
}
atl_weather <- get_table("ATL", date_rng[1])
现在我遍历其余日期,为每个日期创建一个新的 df,然后我尝试将其附加到原始日期:
# Loop through remaining dates and bind dfs
for(d in as.list(date_rng[2:4])){
rbind(atl_weather, get_table("ATL", d), d)
}
但是绑定没有发生,我只剩下范围内第一个日期的原始数据框,它是在 for 循环之前创建的。
这虽然有效:
atl_weather <- get_table("ATL", date_rng[1])
new_df <- get_table("ATL", date_rng[2])
new_df <- scraped_data_formatter(new_df, date_rng[2])
rbind(atl_weather, new_df)
如何让 rbind() 在 for 循环中工作(以便我迭代构建数据框以包含完整日期范围内的所有数据)?
确实有效。问题是您丢弃了结果,因为您没有将 rbind()
的输出分配给任何东西。
改变
rbind(atl_weather, get_table("ATL", d), d)
至此
atl_weather <- rbind(atl_weather, get_table("ATL", d), d)
假设 atl_weather
是您要增量添加的数据框。
就是说,您不想在 R 中这样做;每次向对象添加 column/row 时,R 都需要进行大量数据复制。基本上,以这种方式递增增长的对象会产生大量开销,这样做肯定会让您的代码陷入困境。
理想情况下,您首先分配足够的 space(即足够的行以便您可以在分配时索引第 i
行:new_atl_weather[i, ] <- c(....)
。)
我会冒着跑题的风险(因为这个问题已经得到正确回答),只要我被迫在 for 循环中构建数据框,我就会为您提供我最喜欢的编程模式:
for (d in as.list(date_rng[2:4])){
if (exists("atl_weather")) {
atl_weather = rbind(atl_weather, get_table("ATL", d), d)
} else {
atl_weather = get_table("ATL", d)
}
}
当然,如果我有 get_table
中包含的功能,我会改用某种 apply
语句。但是当现实生活妨碍并且 for 循环的内部太复杂时,我通常会使用类似的模式将某种 temp.data.frame
对象分配给或绑定到 atl_weather
以上:
if (exists("atl_weather")) rm(atl_weather) # in case I'm dynamically running code in chunks
for (d in as.list(date_rng[2:4])){
temp.df = ... # complicated stuff
if (exists("atl_weather")) {
atl_weather = rbind(atl_weather, temp.df)
} else {
atl_weather = temp.df
}
}