用计算值填充大数据框

时间:2018-08-18 03:16:21

标签: r dataframe

我有一个相当大的数据框(1.65 MM行),看起来像这样:

  date        dayofyear time humidity temp
1 2008-01-01         1  300       99  38.2
2 2008-01-01         1  302       99  38.5
3 2008-01-01         1  304       99  38.5
4 2008-01-01         1  306       99  38.6
5 2008-01-01         1  308       99  38.9
6 2008-01-01         1  310       99  39.1
....

我想计算每一行的太阳正午,并将其作为新列添加到数据框中。 suncalc::getSunlightTimes(date)函数使我可以在任何给定日期输入太阳正午。

如果我这样做:

solarNoons <- suncalc::getSunlightTimes(date = as.Date(dataFrame$date))

然后(显然)即使一个小时后,命令也不会完成。

一项观察-即使数据框中有1.65毫米的行,但只有约3000个唯一的日期。解决此问题的最佳方法是什么?只能调用一次getSunlightTimes() 3000次,并且仍然用新列中的值填充数据帧的1.65 MM行中的每一行吗?

这是我的第一次发贴,但是长时间的阅读和学习。非常感谢。

2 个答案:

答案 0 :(得分:0)

仅在df$date的每个不同值上调用一次昂贵的函数。现在,您将只调用3000次而不是165m次。应该快550倍。还要应用@RonakShah建议的任何特定于功能的加速技巧。

# Assign df$date <- as.Date(df$date) as early as possible, ideally right after you read it in    
df$date <- as.Date(df$date)

library(dplyr)

df <- df %>% group_by(date) %>%
             mutate(solarNoon = suncalc::getSunlightTimes(df$date, ...))

两种确保每个日期只打一次suncalc::getSunlightTimes()的方法:

  1. group_by(date) %>% ...插入您的suncalc::getSunlightTimes(df$date, ...)通话
  2. use caching

我赞成方法1,因为它很容易编码,并且通常会教给您很好的分解方法。始终尝试构建代码,以避免不必要地调用昂贵的函数一百万次。

答案 1 :(得分:0)

以下应该起作用。假设我们生成了一个200万行的数据框:

> N <- 2e6
> R <- data.frame(year = sample(2000:2009,N,TRUE),
+                 dayofyear = sample(365,N,TRUE),
+                 time = floor(runif(N,0,12))*100+floor(runif(N,0,60)),
+                 humidity = 99,
+                 temp = floor(runif(N,15,40)))
> R$date <- as.Date(with(R,strptime(paste(year,dayofyear),
+                                   "%Y %j", tz="GMT")))
> nrow(R)
[1] 2000000
> head(R)
  year dayofyear time humidity temp       date
1 2000       206  307       99   39 2000-07-24
2 2009       101 1019       99   16 2009-04-11
3 2004       307  547       99   21 2004-11-02
4 2003       270 1158       99   33 2003-09-27
5 2006        21  330       99   22 2006-01-21
6 2005       154  516       99   21 2005-06-03
> 

在这种情况下,date已经是Date列,但是如果您是字符列,则:

> R$date <- as.Date(R$date)

应该只需要几秒钟。

现在,获取所有唯一日期值的列表。这应该很快:

> dates <- unique(R$date)
> print(length(dates))
[1] 3650
> 

现在,在此向量上运行getSunlightTimes。使用suncalc版本0.4和R版本3.4.4在我的机器上只花了几秒钟:

> times <- suncalc::getSunlightTimes(dates, lat=0, lon=0)

现在,生成一个索引向量,以给出唯一日期R$date的向量内dates中每个日期的索引:

> i <- match(R$date, dates)

现在,通过相同的索引选择times数据帧的行:

> solarNoons <- times[i,]
> nrow(solarNoons)
[1] 2000000
> 

如果我们选择一行R:

> R[1234567,]
        year dayofyear time humidity temp       date
1234567 2002        24  535       99   17 2002-01-24

您会看到solarNoons的相应行是该日期的结果:

> solarNoons[1234567,]
                        date lat lon           solarNoon               nadir
2616.352 2002-01-24 12:00:00   0   0 2002-01-24 12:13:14 2002-01-24 00:13:14
                     sunrise              sunset          sunriseEnd
2616.352 2002-01-24 06:09:42 2002-01-24 18:16:46 2002-01-24 06:11:58
                 sunsetStart                dawn                dusk
2616.352 2002-01-24 18:14:30 2002-01-24 05:47:49 2002-01-24 18:38:39
                nauticalDawn        nauticalDusk            nightEnd
2616.352 2002-01-24 05:22:22 2002-01-24 19:04:06 2002-01-24 04:56:50
                       night       goldenHourEnd          goldenHour
2616.352 2002-01-24 19:29:38 2002-01-24 06:38:39 2002-01-24 17:47:49
> 

如果需要,可以将两个数据框合并在一起:

> R2 <- cbind(R, solarNoons)

所有这些都假设“ 1.65 MM”表示165万。如果您的意思是165亿(即一万亿美元),那么您将需要一台更大的计算机。