如何在stargazer中以科学计数法显示系数

12
我想在 R 中使用stargazer或类似工具将不同模型(lm、glm、plm、pglm)的结果进行比较,呈现在一个表格中。 然而,我无法找到一种方法来以科学计数法显示系数。这有点问题,因为拦截项非常大(约为百万级),而其他系数很小(约为e-7),导致出现许多无用的零,使得读取表格更加困难。
我在这里找到了一个类似的问题:Format model display in texreg or stargazer R as scientific。 但那里的结果需要重新调整变量,而我使用的是计数数据,不想对其进行重新调整。
非常感谢任何建议。

这个问题有一定相关性,但直接并不适用于这里:https://dev59.com/VZbfa4cB1Zd3GeqPnQIO - landroni
3个回答

5
以下是一个可复制的示例:

m1 <- lm(Sepal.Length ~ Petal.Length*Sepal.Width,
         transform(iris, Sepal.Length = Sepal.Length+1e6,
                   Petal.Length=Petal.Length*10, Sepal.Width=Sepal.Width*100))
# Coefficients:
#              (Intercept)              Petal.Length               Sepal.Width  Petal.Length:Sepal.Width  
#                1.000e+06                 7.185e-02                 8.500e-03                -7.701e-05  

我不认为stargazer能够轻松支持这个功能。 你可以尝试其他替代方案,如xtable这里的众多选项(我没有尝试过它们全部)。

library(xtable)
xtable(m1, display=rep('g', 5)) # or there's `digits` too; see `?xtable`

如果你正在使用knitrpandoc,我非常喜欢pander,它已经具备了自动科学计数法(注意:这是类似于markdown格式的pandoc输出,而不是tex输出,然后你可以将其转换为latex/pdf):

library(pander)
pander(m1)

好的,谢谢。你知道有哪个包支持pglm模型吗?我尝试了你发布的列表中的几个,但到目前为止都没有成功。 - Lukas Stäcker
pglm非常特殊。甚至您最初的选择stargazer也不支持它。我认为您将不得不将其转换为漂亮的格式(例如,转换为数据框,然后使用一个可以生成其latex的包)。 - mathematical.coffee

4

建议联系软件包维护者,提出新增此选项的功能请求。

同时,您可以使用科学计数法自动替换输出中的数字。但是,在替换数字时需要注意几件事情。重要的是不要重新格式化LaTeX编码中的数字。此外,要注意不要替换变量名中的字符。例如,Sepal.Width中的.可能会被正则表达式误认为是数字。下面的代码应该能够处理常见的大部分情况。但是,如果有人将他们的变量称为X_123456789,根据scipen设置,它可能会将其重命名为X_1.23e+09。因此需要一些谨慎,并且stargazer软件包可能需要实现更健壮的解决方案。

以下是一个示例stargazer表格,可用于演示(无耻地复制自@mathematical.coffee):

library(stargazer)
library(gsubfn)
m1 <- lm(Sepal.Length ~ Petal.Length*Sepal.Width,
  transform(iris, Sepal.Length = Sepal.Length+1e6,
    Petal.Length=Petal.Length*10, Sepal.Width=Sepal.Width*100))    
star = stargazer(m1, header = F, digit.separator = '')

现在有一个辅助函数来重新格式化数字。您可以玩弄数字和scipen参数以控制输出格式。如果您想更经常地使用科学格式,请使用较小(更负)的scipen。否则,我们可以通过使用更大的scipen使其自动仅对非常小或大的数字使用科学格式。 cutoff参数用于防止只由几个字符表示的数字重新格式化。

replace_numbers = function(x, cutoff=4, digits=3, scipen=-7) {
  ifelse(nchar(x) < cutoff, x, prettyNum(as.numeric(x), digits=digits, scientific=scipen))
}

使用 gsubfn::gsubfn 将其应用于stargazer输出结果。

gsubfn("([0-9.]+)", ~replace_numbers(x), star)

enter image description here


问题在于@dww和当前答案并不能让您以正确的科学记数法表示,即X.Ye+(Z)。上面的输出显示了这个问题,您知道我的意思吗? - wolfsatthedoor
不太确定我是否理解了。您的意思是,您想要类似于1.5 x 10$^3$而不是1.5e+03这样的东西吗? - dww
不,我的意思是,1e+06应该是1.2e+06或其他什么。小数位应该保持一致。例如,你不希望在下一行看到8.44e-01和8.4e-01。你希望看到8.44e-01,然后是8.40e-01(如果是这样的话)。(上面的R ^ 2示例) - wolfsatthedoor
好的 - 我明白了。我编辑了另一个答案(那个有赏金的)并使用了sprintf而不是prettyNum。这使得科学计数法中始终具有相同数量的数字(保留任何尾随零)。如果需要,也可以对此版本进行相同的更改。 - dww

4
另一种使用stargazer获取科学计数法的强大方法是通过修改digit.separator参数。该选项允许用户指定分隔小数的字符(在大多数地区通常为点.)。我们可以篡改此参数,将唯一可识别的字符串插入到任何要使用正则表达式查找的数字中。以这种方式搜索数字的优点是,我们只能找到与stargazer输出中的数值相对应的数字。即,没有可能同时匹配变量名称的数字(例如X_12345)或作为latex格式化代码的一部分的数字(例如\hline \\[-1.8ex])。在下面的例子中,我使用字符串::::,但任何我们在表格中找不到的唯一字符串(如哈希)都可以。最好避免在标识符标记中有任何特殊的正则表达式字符,因为这会稍微复杂一些。

使用this other answer中的示例模型m1

mark  = '::::'
star = stargazer(m1, header = F, decimal.mark  = mark, digit.separator = '')

replace_numbers = function(x, low=0.01, high=1e3, digits = 3, scipen=-7, ...) {
  x = gsub(mark,'.',x)
  x.num = as.numeric(x)
  ifelse(
    (x.num >= low) & (x.num < high), 
    round(x.num, digits = digits), 
    prettyNum(x.num, digits=digits, scientific = scipen, ...)
  )
}    

reg = paste0("([0-9.\\-]+", mark, "[0-9.\\-]+)")
cat(gsubfn(reg, ~replace_numbers(x), star), sep='\n')

enter image description here

更新 如果您想确保科学计数法中保留尾随零,则可以使用sprintf而不是prettyNum。

像这样

replace_numbers = function(x, low=0.01, high=1e3, digits = 3) {
  x = gsub(mark,'.',x)
  x.num = as.numeric(x)
  form = paste0('%.', digits, 'e')
  ifelse(
    (abs(x.num) >= low) & (abs(x.num) < high), 
    round(x.num, digits = digits), 
    sprintf(form, x.num) 
  )
}

enter image description here


我喜欢这个答案,因为它明确说明了如何不转换中等值,而只转换极端值。但我遇到的一个问题是,回归结果的coef's是10^-8,所以我需要输入很多位数,以免所有结果都变成0。虽然这样做没问题,但最后的R^2看起来像.0131575939。有没有一种方法可以将所有未转换的小数四舍五入到千分位? - wolfsatthedoor
很好的观点@wolfsatthedoor - 我编辑了它,使用round在中等值上,这样您也可以指定这些值的小数位数。这样做是否符合您的要求? - dww
我给你悬赏是为了安全起见,现在让我检查一下,非常好的答案。我预测随着学术界越来越多地采用集成的Markdown文档,这将是一个更具关注度的问题! - wolfsatthedoor
你能更具体地解释一下 scipen = -7 是什么意思吗?另外,四舍五入也有效果,但像 .003 这样的数字却没有被转换成科学计数法。 - wolfsatthedoor
1
抱歉 - 在这个版本中忘记将 scipen 传递给 PrettyNum。现已更正。基本上,scipen 是科学计数法与标准计数法之间数字位数的差异,以优先使用科学计数法为准。较小(更负)的值会更积极地强制使用科学计数法。 - dww

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接