首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在R中正确聚合嵌套行和reactable?

如何在R中正确聚合嵌套行和reactable?
EN

Stack Overflow用户
提问于 2020-08-28 03:02:50
回答 2查看 535关注 0票数 0

我正在开发一个闪亮的应用程序,由于我的数据的嵌套结构,reactable包非常有用。它允许我在更高级别的类别中折叠和汇总行,并且只有在需要时才展开以显示“子行”。

对于仅1个嵌套级别(例如,makes中的汽车模型),聚合函数(uniquecount等)来自reactable的开箱即用的工作很好。然而,当添加额外的嵌套级别时,事情就会崩溃,甚至像unique这样的聚合器也会出现重复的值(!)。我怀疑这是因为子类别并不都汇集在一个平面结构中,只对所有子类别执行一个聚合步骤,而是唯一的值仍然是子类别特定的,然后只是连接在一起,导致重复。这个问题也会影响到其他聚合器,不仅仅是unique

我在下面的R中添加了一个MWE,因为我一直无法修复这个问题。由于JS也远不是我的强项,我无法插入任何JS来更灵活地修复这个问题,正如here所建议的那样。如何调整下面的聚合器以获得正确显示的输出(即无重复)?

代码语言:javascript
复制
library(shiny)
library(shinydashboard)
library(reactable)
library(stringr)

if (interactive()) {
  
  ui <- shinyUI(basicPage(
    box(title = "mtcars data",
        width = 12,
        reactableOutput("car_tab")
    )
  ))
  
  server <- function(input, output, session) {
    output$car_tab <- renderReactable({
      
      df <- mtcars
      df$make <- str_extract(rownames(df), "[[:alpha:]]+")
      df$model <- rownames(df)
      rownames(df) <- NULL
      df <- df[ , c("make", "model", "mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")]
      
      reactable(df,
                groupBy = c("cyl", "am", "make"),
                columns = list(
                  cyl = colDef(name = "Number of cylinders"),
                  am = colDef(name = "Transmission",
                              aggregate = "frequency"),
                  make = colDef(name = "Make",
                                aggregate = "frequency"),
                  model  = colDef(name = "Model",
                                  aggregate = "unique"),
                  mpg = colDef(name = "Miles/gallon",
                               aggregate = "mean",
                               format = colFormat(digits = 2)),
                  disp = colDef(name = "Displacement"),
                  hp = colDef(name = "Horsepower"),
                  drat = colDef(name = "Rear axle ratio"),
                  wt = colDef(name = "Weight"),
                  qsec = colDef(name = "1/4 mile time"),
                  vs = colDef(name = "Engine",
                              aggregate = "count"),
                  gear = colDef(name = "Number of forward gears"),
                  carb = colDef(name = "Number of carburetors")
                )
      )
    })
  }
  
  shinyApp(ui = ui, server = server)
  
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-15 07:43:32

我认为这可以通过使用聚合器来解决,因为您现在正在使用它们,然后通过colDefaggregated参数提供一个自定义的JavaScript渲染器。其想法是reactable将通过内置运算符进行聚合,并将使用自定义渲染器在聚合单元格中呈现输出。

定制的JavaScript呈现器应该接受一个看起来像0, 0(2), 1(6), 1(2)的字符串,并执行一些字符串操作来生成一个像0(3), 1(8)这样的输出。

如果像这样定义JavaScript函数并将其保存在R变量中,则可以重用它:

代码语言:javascript
复制
jsRenderer <- "
    function(cellInfo) {
        const handleBrackets = (item) => {
            const currentName = item.replace(/\\([0-9]+\\)/g, '')
            const currentCountsArr = item.match(/\\(([0-9]+)\\)/)
            let currentCount = 1
            if (currentCountsArr && currentCountsArr.length === 2) {
                currentCount = parseInt(currentCountsArr[1], 10)
            }
            return {
                currentName,
                currentCount
            }
        }

        const getCounts = (input) => {
            const trimmedInput = input.replace(/\\s+/g, '')
            const items = trimmedInput.split(',')
            const namesWithoutBrackets = trimmedInput.replace(/\\(([0-9]+)\\)/g, '').split(',')
            const itemObj = items.reduce((prev, current, index) => {
                const itemWithoutBrackets = handleBrackets(current)
                let {
                    currentName,
                    currentCount
                } = itemWithoutBrackets

                if (namesWithoutBrackets.indexOf(currentName) !== index) {
                    currentCount += prev[currentName]
                }

                return {
                    ...prev,
                    ...{
                        [currentName]: currentCount
                    }
                }

            }, {})

            const stringToSanitize = Object.entries(itemObj).reduce((prevString, currentKeyValue) => {
                return prevString.concat(`${currentKeyValue[0]}(${currentKeyValue[1]}), `)
            }, '')

            return stringToSanitize.slice(0, -2)
        }

        return (getCounts(cellInfo.value))
    }
"

然后,可以将渲染后的内容提供给colDef,如下所示:

代码语言:javascript
复制
colDef(name = "Transmission", aggregate = "frequency", aggregated = jsRenderer)

在MWE中,结果显示如下:

代码语言:javascript
复制
Merc(2),
Toyota(2),
Datsun(1),
Fiat(2),
Honda(1),
Porsche(1),
Lotus(1),
Volvo(1)
票数 1
EN

Stack Overflow用户

发布于 2020-08-28 19:10:56

要获取0(3), 1(8),您需要

代码语言:javascript
复制
groupBy = c("cyl", "am")

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63622632

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档