如何在不使用for循环的情况下合并需要提前3个月的列上的两个数据框
Posted
技术标签:
【中文标题】如何在不使用for循环的情况下合并需要提前3个月的列上的两个数据框【英文标题】:How to merge two dataframes on a column that needs to be 3 months ahead without using for loop 【发布时间】:2018-03-19 14:03:07 【问题描述】:我有在 R 中对列值在两个数据帧之间匹配的数据帧使用 inner_join 函数的经验。但是,我有一个数据框包含 2007-2014 年每只股票每个月的平均股价,另一个数据框包含 2007-2014 年每只股票的财务比率,并显示每家公司的财政年度结束月份。问题是,一家公司的财务比率要到 3 个月后发布 10K 才能报告。因此,我想将每家公司的财务比率与其合适的股票价格相匹配,即 3 个月后。
比率DF:
Symbol Month Year 10KRatio1 10KRatio2 ... 10KRatioN
FLWS 6 2007 100 200 ... 1000
ACAD 12 2007 500 600 ... 2000
StockPriceDF:
Company Year Month MeanPrice
FLWS 2007 1 6.32
. . . .
. . . .
. . . .
FLWS 2007 9 10.995
. . . .
. . . .
. . . .
FLWS 2014 12 17.92
. . . .
ACAD 2007 1 7.5
. . . .
. . . .
. . . .
ACAD 2008 3 8.64
. . . .
. . . .
所需的DF:
Symbol Month Year 10KRatio1 10KRatio2 ... 10KRatioN MeanPrice
FLWS 9 2007 100 200 1000 10.995
ACAD 3 2008 500 600 2000 8.64
我正在考虑使用 for 循环来检查 RatioDF 月份是否为 10-12 月份,然后将其与明年的 1-3 月份匹配以获取适当的符号/公司,但我认为计算可能也需要因为这些年库存很多,月价格也很多。
【问题讨论】:
【参考方案1】:lubridate
和data.table
或dplyr
的可能解决方案。
1) 带有 data.table:
# load packages
library(lubridate)
library(data.table)
# convert both dataframes to data.table's and add a 'date'-variable
setDT(d1)[, date := as.IDate(sprintf('%s-%02d-01',Year,Month))][]
# idem + substract 3 months with lubridate's '%m-%` function
setDT(d2)[, date := as.IDate(sprintf('%s-%02d-01',Year,Month)) %m-% months(3)][]
# join d1 with d2 and update d1 by reference
d1[d2, on = .(Symbol = Company, date), MeanPrice := MeanPrice][]
给出:
Symbol Month Year 10KRatio1 10KRatio2 date MeanPrice 1: FLWS 6 2007 100 200 2007-06-01 10.995 2: ACAD 12 2007 500 600 2007-12-01 8.640
另一种连接方法可能是:
d1[d2[, .(Company, date, MeanPrice)], on = .(Symbol = Company, date), nomatch = 0L][]
2) 使用 dplyr:
# load packages
library(lubridate)
library(dplyr)
# add a 'date'-variable to 'd1'
# add a 'date'-variable to 'd2' and substract 3 months
# from that with lubridate's '%m-%` function
# select only 'Company', 'date' and 'MeanPrice' from 'd2'
# join 'd1' with 'd2'
d1 %>%
mutate(date = as.Date(sprintf('%s-%02d-01',Year,Month))) %>%
left_join(., d2 %>%
mutate(date = as.Date(sprintf('%s-%02d-01',Year,Month)) %m-% months(3)) %>%
select(Company, date, MeanPrice),
by = c('Symbol' = 'Company', 'date'))
给出相同的结果:
Symbol Month Year 10KRatio1 10KRatio2 date MeanPrice 1 FLWS 6 2007 100 200 2007-06-01 10.995 2 ACAD 12 2007 500 600 2007-12-01 8.640
使用过的数据:
d1 <- structure(list(Symbol = c("FLWS", "ACAD"),
Month = c(6L, 12L),
Year = c(2007L, 2007L),
`10KRatio1` = c(100L, 500L),
`10KRatio2` = c(200L, 600L)),
.Names = c("Symbol", "Month", "Year", "10KRatio1", "10KRatio2"), class = "data.frame", row.names = c(NA, -2L))
d2 <- structure(list(Company = c("FLWS", "FLWS", "FLWS", "ACAD", "ACAD"),
Year = c(2007L, 2007L, 2014L, 2007L, 2008L),
Month = c(1L, 9L, 12L, 1L, 3L),
MeanPrice = c(6.32, 10.995, 17.92, 7.5, 8.64)),
.Names = c("Company", "Year", "Month", "MeanPrice"), class = "data.frame", row.names = c(NA, -5L))
【讨论】:
以上是关于如何在不使用for循环的情况下合并需要提前3个月的列上的两个数据框的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 for 循环的情况下将列表中的所有项目与整数进行比较
如何在不使用 for 循环的情况下从 appsettings 文件中读取对象数组中特定键的值