为什么rbind()不在for循环中工作?

时间:2017-09-07 01:00:16

标签: r loops rbind

我有一系列日期:

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循环中工作(这样我就可以迭代地构建数据帧以包含完整日期范围内的所有数据)?

2 个答案:

答案 0 :(得分:5)

确实有效。问题是你丢弃了结果,因为你没有将rbind()的输出分配给任何东西。

更改

rbind(atl_weather, get_table("ATL", d), d)

到这个

atl_weather <- rbind(atl_weather, get_table("ATL", d), d)

假设atl_weather是您想要逐步添加的数据框。

那就是说,你想要在R 中这样做;每次向对象添加列/行时,R都需要进行大量的数据复制。基本上,通过这种方式增量增长对象会带来很多开销,这样做可能会让代码陷入困境。

理想情况下,您首先要分配足够的空间(即足够的行,以便您可以在分配时i索引new_atl_weather[i, ] <- c(....)行。)

答案 1 :(得分:2)

我冒着偏离主题的风险(因为问题已经得到了正确回答),每当我被迫在for循环中构建数据帧时,给你我最喜欢的编程模式:

def get_event_stats(elengths, einds, *args, **kwargs):
    master_list = []
    # Unpack the recognized arguments (with default values), so kwargs left should be empty
    avg = kwargs.pop('avg', False)
    tot = kwargs.pop('tot', False)

    # If any keywords left over, they're unrecognized, raise an error
    if kwargs:
        # Arbitrarily select alphabetically first unknown keyword arg
        raise TypeError('get_event_stats() got an unexpected keyword argument {!r}'.format(min(kwargs)))

    if avg:
        for arg in args:
             do stuff...
    if tot:
        for arg in args:
             do stuff...

    return master_list

当然,如果我有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语句。但是当真实生活受阻并且for循环的内部过于复杂时,我通常会使用类似的模式将某些apply对象分配给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
    }
}