【问题标题】:Working with data.tables within data.tables在 data.tables 中使用 data.tables
【发布时间】:2018-09-24 13:00:47
【问题描述】:

在我的研究中,我经常遇到列表中列表的问题。今天,我再次遇到了一个我不知道如何在 R 中最好地解决的程序。我尝试使用 data.table 解决问题,但遇到了麻烦。

我有各种初创公司的数据,比如Startup1Startup2 等。对于每家初创公司,我都有投资者信息,VC1VC2 等。我也有关于初创公司何时开始活动的信息:StartYr 和以投资者为特征的融资轮次VCNam,这一年是一轮融资发生FRYr,收到的金额FMoney。对于每个 Startup,融资轮次的数量都会发生变化,投资者的数量也会发生变化。

作为第一个练习,我尝试计算StartYr 和给定资助年份之间的时间。这是我的代码:

library(data.table)
    dtF1=data.table(VCNam=c("VC1","VC2"),FRYr=c("2006","2007"),FMoney=c(10000,20000))
    dtF2=data.table(VCNam=c("VC1","VC3","VC4"),FRYr=c("2010","2011","2012"),FMoney=c(10,20,30))
    dt=data.table(FirmName=c("Startup1","Startup2"),StartYr=c("2001","2005"),FdRounds=c(dtF1,dtF2))
dt[]

FNams=unique(dt$FirmName)
for (nam in FNams){
     print(paste("dealing with firm",nam))
     dtSub=dt[FirmName==nam,.(StartYr,FdRounds)]
     StartYr=as.integer(dtSub[,StartYr])
     print(StartYr)
     print(dtSub[,FdRounds][[1]])
     print(dtSub[,FdRounds][[2]])
     FRYr=dtSub[,FdRounds][[3]]
     print(as.integer(FRYr)-StartYr)
}

这是我的输出:

> dt[]
   FirmName StartYr       FdRounds
1: Startup1    2001        VC1,VC2
2: Startup2    2005      2006,2007
3: Startup1    2001    10000,20000
4: Startup2    2005    VC1,VC3,VC4
5: Startup1    2001 2010,2011,2012
6: Startup2    2005       10,20,30

and:
[1] "dealing with firm Startup1"
[1] 2001 2001 2001
[1] "VC1" "VC2"
[1] 10000 20000
[1]  9 10 11 # the right answer
[1] "dealing with firm Startup2"
[1] 2005 2005 2005
[1] "2006" "2007"
[1] "VC1" "VC3" "VC4"
[1] -1995 -1985 -1975 # a crazy answer.

Startup1 的结果 9 10 11 是正确的,但 Startup2 的结果是 -1995 等。检查发现 dt 不再包含正确的元素顺序:VC 名称、资助年份、资金。

问题 1:我愿意使用列表、dplyr 或 data.table,这是解决此问题的建议方法。数据是数百家公司,所以时间是个问题。

问题 2:如何解决这个代表我一直遇到的问题的问题?相关:有没有更函数化的编程方式来处理这个问题?

【问题讨论】:

  • 感谢您提出的问题以及对样本数据的详细解释。

标签: r dplyr data.table


【解决方案1】:

由于底层数据结构的复杂设计,很难分析为什么for 循环会返回错误的答案。另一个问题是 FRYrStartYr 作为字符给出,但 OP 想要计算它们的差异。

因此,我建议以类似 SQL 的方式使用仅包含两个 data.tables 的“干净”设计:

  1. 一个用于所有融资回合FdRounds
  2. 一秒用于所有创业公司的基础数据Startup

使用FirmName 作为键来识别两个表中属于彼此的行。

这些可以从现有数据构建:

library(data.table)
dtF1 = data.table(
  FirmName = "Startup1",
  VCNam = c("VC1", "VC2"),
  FRYr = c("2006", "2007"),
  FMoney = c(10000, 20000)
)
dtF2 = data.table(
  FirmName = "Startup2",
  VCNam = c("VC1", "VC3", "VC4"),
  FRYr = c("2010", "2011", "2012"),
  FMoney = c(10, 20, 30)
)
FdRounds <- rbindlist(list(dtF1, dtF2))
FdRounds[, FRYr := as.integer(FRYr)]
FdRounds
   FirmName VCNam FRYr FMoney
1: Startup1   VC1 2006  10000
2: Startup1   VC2 2007  20000
3: Startup2   VC1 2010     10
4: Startup2   VC3 2011     20
5: Startup2   VC4 2012     30
Startups = data.table(
  FirmName = c("Startup1", "Startup2"),
  StartYr = c("2001", "2005")
)
Startups[, StartYr := as.integer(StartYr)]

现在,我们可以连接两个表并进行计算

FdRounds[Startups, on = "FirmName"][, FdYearAfterStart := FRYr - StartYr][]
   FirmName VCNam FRYr FMoney StartYr FdYearAfterStart
1: Startup1   VC1 2006  10000    2001                5
2: Startup1   VC2 2007  20000    2001                6
3: Startup2   VC1 2010     10    2005                5
4: Startup2   VC3 2011     20    2005                6
5: Startup2   VC4 2012     30    2005                7

为了更紧凑的视图,可以按初创公司汇总数据:

FdRounds[Startups, on = "FirmName"][, FdYearAfterStart := FRYr - StartYr][
  , lapply(.SD, toString), by = .(FirmName, StartYr)]
   FirmName StartYr         VCNam             FRYr       FMoney FdYearAfterStart
1: Startup1    2001      VC1, VC2       2006, 2007 10000, 20000             5, 6
2: Startup2    2005 VC1, VC3, VC4 2010, 2011, 2012   10, 20, 30          5, 6, 7

从合并结果可以很容易地计算出每家初创公司从所有投资者那里获得的总资金:

FdRounds[Startups, on = "FirmName"][
  , .(TotalFunding = sum(FMoney)), by = .(FirmName, StartYr)][]
   FirmName StartYr TotalFunding
1: Startup1    2001        30000
2: Startup2    2005           60

这种方法也更加通用,因为它也允许投资者进行汇总:

FdRounds[Startups, on = "FirmName"][
  , .(NumberFR = .N, TotalFunding = sum(FMoney), 
      InYears = paste(range(FRYr), collapse = "-")), by = VCNam]
   VCNam NumberFR TotalFunding   InYears
1:   VC1        2        10010 2006-2010
2:   VC2        1        20000 2007-2007
3:   VC3        1           20 2011-2011
4:   VC4        1           30 2012-2012
FdRounds[Startups, on = "FirmName"][
  , .(NumberFR = .N, TotalFunding = sum(FMoney), 
      InvestedIn = toString(FirmName)), by = VCNam]
   VCNam NumberFR TotalFunding         InvestedIn
1:   VC1        2        10010 Startup1, Startup2
2:   VC2        1        20000           Startup1
3:   VC3        1           20           Startup2
4:   VC4        1           30           Startup2

【讨论】:

  • 感谢我的工作!优秀的答案。不幸的是,我还没有足够的经验来归因。
  • ...而且,您还回答了我心中的一个问题,即资金的汇总。很聪明!谢谢!!
  • @MichaelRockinger 我很高兴猜到您的要求。即使您没有足够的声誉,您也可以在方便时将答案标记为已接受。
猜你喜欢
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
  • 2013-03-06
  • 2012-10-27
相关资源
最近更新 更多