【问题标题】:convert triple nested list to dataframe将三重嵌套列表转换为数据框
【发布时间】:2018-04-29 21:47:28
【问题描述】:

我正在尝试将三重嵌套列表转换为数据框。 This 问题有所帮助,但我无法获得我想要的数据框。

该列表是从 IBrokers 获得的一个期权链,摘要如下所示。我已经上传了更详细的实际链here

Chain <- 
  list(
    list(
      list(
        list(version="8",contract=list(symbol="BHP",right="C",expiry="20180621",strike="25")),
        list(version="8",contract=list(symbol="BHP",right="C",expiry="20180621",strike="26"))
      ),
      list(
        list(version="8",contract=list(symbol="BHP",right="C",expiry="20180730",strike="25")),
        list(version="8",contract=list(symbol="BHP",right="C",expiry="20180730",strike="26"))
      )
    ),
    list(
      list(
        list(version="8",contract=list(symbol="CBA",right="C",expiry="20180621",strike="65")),
        list(version="8",contract=list(symbol="CBA",right="C",expiry="20180621",strike="64"))
      ),
      list(
        list(version="8",contract=list(symbol="CBA",right="C",expiry="20180730",strike="65")),
        list(version="8",contract=list(symbol="CBA",right="C",expiry="20180730",strike="64"))
      )
    )
  )

我想将列表转换成这样的数据框:

Contracts <- data.frame(symbol=c("BHP","BHP","BHP","BHP","CBA","CBA","CBA","CBA"),
                        right=c("C","C","C","C","C","C","C","C"),
                        expiry=c("20180621","20180621","20180730","20180730","20180621","20180621","20180730","20180730"),
                        strike=c("25","26","25","26","65","64","65","64"))

我尝试了这段代码,但它没有给我想要的数据框。

X <- lapply(Chain,function(x) as.data.frame.list(lapply(x,as.data.frame.list)))
dfx <- do.call(rbind,X)

有什么建议吗?

【问题讨论】:

    标签: r nested-lists ibrokers


    【解决方案1】:

    下面的呢?

    df <- as.data.frame(matrix(unlist(Chain, recursive = T), ncol = 5, byrow = T)[, -1]);
    colnames(df) <- c("symbol", "right", "expiry", "strike");
    #  symbol right   expiry strike
    #1    BHP     C 20180621     25
    #2    BHP     C 20180621     26
    #3    BHP     C 20180730     25
    #4    BHP     C 20180730     26
    #5    CBA     C 20180621     65
    #6    CBA     C 20180621     64
    #7    CBA     C 20180730     65
    #8    CBA     C 20180730     64
    

    解释:递归unlist嵌套Chain,然后重铸为matrix,删除列version并转换为data.frame。唯一的小缺点是我们必须手动添加列名。


    更新

    由于您的实际数据完全不同,这里有一种可能性。 注意:我假设 Gist 中的结构存储在 tbl

    tbl;
    #Source: local data frame [2 x 6]
    #Groups: <by row>
    #
    ## A tibble: 2 x 6
    #  symbol sectype exch  currency multiplier Chain
    #  <fct>  <fct>   <fct> <fct>    <fct>      <list>
    #1 BHP    OPT     ASX   AUD      100        <list [1,241]>
    #2 CBA    OPT     ASX   AUD      100        <list [1,204]>
    

    以下list 包含两个data.frames,每行一个对应tbl

    lst <- lapply(tbl$Chain, function(x)
        do.call(rbind.data.frame, lapply(x, function(y) as.data.frame(unclass(y$contract)))))
    #List of 2
    # $ :'data.frame':  1241 obs. of  16 variables:
    #  ..$ conId          : Factor w/ 1241 levels "198440202","198440207",..: 1 2 3 4 5 6 7 8 9 10 ...
    #  ..$ symbol         : Factor w/ 1 level "BHP": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ sectype        : Factor w/ 1 level "OPT": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ exch           : Factor w/ 1 level "ASX": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ primary        : Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ expiry         : Factor w/ 18 levels "20180628","20181220",..: 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ strike         : Factor w/ 118 levels "25","26","27",..: 1 1 2 2 3 3 4 4 5 5 ...
    #  ..$ currency       : Factor w/ 1 level "AUD": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ right          : Factor w/ 2 levels "C","P": 1 2 1 2 1 2 1 2 1 2 ...
    #  ..$ local          : Factor w/ 1241 levels "BHPV78","BHPV88",..: 1 2 3 4 5 6 7 8 9 10 ...
    #  ..$ multiplier     : Factor w/ 1 level "100": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ combo_legs_desc: Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ comboleg       : Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ include_expired: Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ secIdType      : Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ secId          : Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    # $ :'data.frame':  1204 obs. of  16 variables:
    #  ..$ conId          : Factor w/ 1204 levels "198447027","198447030",..: 1 2 3 4 5 6 7 8 9 10 ...
    #  ..$ symbol         : Factor w/ 1 level "CBA": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ sectype        : Factor w/ 1 level "OPT": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ exch           : Factor w/ 1 level "ASX": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ primary        : Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ expiry         : Factor w/ 18 levels "20180628","20181220",..: 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ strike         : Factor w/ 179 levels "79.68","81.68",..: 1 1 2 2 3 3 4 4 5 5 ...
    #  ..$ currency       : Factor w/ 1 level "AUD": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ right          : Factor w/ 2 levels "C","P": 1 2 1 2 1 2 1 2 1 2 ...
    #  ..$ local          : Factor w/ 1204 levels "CBAKT9","CBAKU9",..: 1 2 3 4 5 6 7 8 9 10 ...
    #  ..$ multiplier     : Factor w/ 1 level "100": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ combo_legs_desc: Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ comboleg       : Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ include_expired: Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ secIdType      : Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    #  ..$ secId          : Factor w/ 1 level "": 1 1 1 1 1 1 1 1 1 1 ...
    

    【讨论】:

    • 谢谢,这也适用于不均匀列表。添加列名不是问题。
    • 我无法在我上传到问题的实际链上得到您的答案。你能用实际的链条再试一次吗?
    • @Zeus 您的实际链与您的示例数据具有非常不同的结构。显然我的解决方案不起作用,因为它基于您的示例数据中的键。 TBH,您的链数据非常笨重(它是一个庞大、复杂且嵌套的list,其中的键在条目之间不一致),我什至不确定您要提取哪些条目。抓取数据时是否可以直接提取相关位?
    • 对不起,我的错误,我应该首先上传列表。不幸的是,我无法控制如何从代理返回数据。我不想要所有信息,只想要列表中的数据.. .. ..$contract
    • @Zeus 但是您提供的数据似乎是两行tibble,在Chain 列中嵌套了list。是您要从中提取.. .. ..$contract 的上述Chain 吗?由于您有两行,因此您也有两个嵌套列表。对吗?
    【解决方案2】:

    您可以使用unstack

     unstack(data.frame(d<-unlist(Chain),names(d)))
      contract.expiry contract.right contract.strike contract.symbol version
    1        20180621              C              25             BHP       8
    2        20180621              C              26             BHP       8
    3        20180730              C              25             BHP       8
    4        20180730              C              26             BHP       8
    5        20180621              C              65             CBA       8
    6        20180621              C              64             CBA       8
    7        20180730              C              65             CBA       8
    8        20180730              C              64             CBA       8
    

    如果你愿意,你可以删除contract这个词。

    unstack(data.frame(d<-unlist(Chain),sub(".*[.]","",names(d))))
        expiry right strike symbol version
    1 20180621     C     25    BHP       8
    2 20180621     C     26    BHP       8
    3 20180730     C     25    BHP       8
    4 20180730     C     26    BHP       8
    5 20180621     C     65    CBA       8
    6 20180621     C     64    CBA       8
    7 20180730     C     65    CBA       8
    8 20180730     C     64    CBA       8
    

    这也可以写成unstack(data.frame(d&lt;-unlist(Chain),sub("contract[.]","",names(d)))) 虽然我更愿意维护名称合同以便知道哪些列确实构成了所需的合同数据框

    或者你甚至可以在unstacking之后更改名称。

    使用新数据:

    a=readLines("https://raw.githubusercontent.com/hughandersen/OptionsTrading/master/Stocks_option_chain")
    b=eval(parse(text=paste(a,collapse="")))
    s=unstack(data.frame(d<-unlist(b[6]),names(d)))
    

    【讨论】:

    • 答案不适用于实际的选项链 - 我会尝试将实际链输出作为问题的输入链接,我认为虚拟列表过于简化
    • 真的吗?呵呵..也许尝试在unlist中使用recursive=T..我不知道为什么
    • 我已将实际链上传到问题 - 如果您在下载时遇到问题,请告诉我
    • 感谢您的帮助,这适用于完整列出的选项链。我从没听说过unstack
    • 希望您使用的是Rgui 而不是Rstudio,因为该文件非常庞大。我猜超过 25MB
    猜你喜欢
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多