Python 中的描述性统计数据 /with Pandas with std in the parentheses

Descriptive statistics in Python /with Pandas with std in parentheses

这个问题涉及在 Python 中进行描述性统计的最佳实践,其格式化输出对应于学术出版物中的 tables:均值及其各自的标准偏差在下面的括号中。最终目标是能够以 Latex 表格格式(或其他格式,html 等)导出它。

示例 (Deucherta & Eugster (2018)):

Pandas:

在 Pandas 中进行描述性统计的经典解决方案是使用 DataFrame.

describe() 方法
import numpy as np
import pandas as pd 

# Generate a DataFrame to have an example 
df = pd.DataFrame(
    {"Age" : np.random.normal(20,15,5), 
     "Income": np.random.pareto(1,5)*20_000 }
    )
# The describe method to get means and stds
df.describe().loc[["mean", "std"]].T
>>>
                mean            std
Age        15.322797      13.449727
Income  97755.733510  143683.686484

我想要的是以下输出:

Age        15.32 
          (13.44)
Income  97755.73  
        (143683.68)

如果有一个适用于多索引 Dataframe 的解决方案就好了:

df2 = pd.DataFrame(
    {"Age" : np.random.normal(20,15,5), 
     "Income": np.random.pareto(1,5)*20_000 }
    )
df_c = pd.concat([df,df2], keys = ["A", "B"])
>>>

并获得

                A           B
Age          23.15       21.33
            (11.62)      (9.34)
Income    68415.53    46619.51
         (95612.40)  (64596.10)

我目前的解决方案:

idx = pd.IndexSlice
df_desc = (df_c
      ).groupby(level = 0, axis = 0).describe()
df_desc = df_desc.loc[idx[:],idx[:,["mean", "std"]]].T
df_desc.loc[idx[:,["std"]],idx[:]] = df_desc.loc[idx[:,["std"]],idx[:]
                                               ].applymap(
                                               lambda x: "("+"{:.2f}".format(x)+")")
print(df_desc)

>>>
                     A           B
Age    mean     23.1565     21.3359
      std      (11.62)      (9.34)
Income mean     68415.5     46619.5
      std   (95612.40)  (64596.10)
问题 1:

我没有找到隐藏第二个索引列[mean, std, mean,std]的解决方案。

然后我想将我的 df 导出到乳胶:

df_desc.to_latex()

>>>
\begin{tabular}{llll}
\toprule
       &     &            A &           B \
\midrule
Age & mean &       5.5905 &     29.5894 \
       & std &      (16.41) &     (13.03) \
Income & mean &       531970 &     72653.7 \
       & std &  (875272.44) &  (79690.18) \
\bottomrule
\end{tabular}
问题二:

table 的 & 个字符没有对齐,这使得编辑起来有点乏味(我使用扩展名来对齐 VSCode 中的 &

总的来说,我觉得这个解决方案乏味而且不够优雅。

解决方案?

我不知道在没有复杂的字符串操作的情况下我应该怎么做才能获得所需的结果。

我看过 Pandas styling,但我认为这不是最佳解决方案。

还有StatModels Tables,但我没有找到解决我问题的简单方法。 Statsmodels Tables 似乎是最有前途的解决方案。但我不知道如何实施。 StatsModels 中有一些描述性统计函数,但我在 GitHub 上读到它们在某种程度上已被弃用。

那么制作这些 table 的最佳方法是什么?

我刚刚 运行 遇到了类似的问题并找到了你的 post,所以我是这样处理你提到的问题的。

问题一:隐藏第二个索引列

我更喜欢解决方案 b),但为了便于说明,请在此处保留 a)

a) droplevel & set_index

df_desc.index.droplevel(level=1)

>>>
Index(['Age', 'Age', 'Income', 'Income'], dtype='object')

将这段代码与 set_index 表达式一起使用:

df_desc.set_index(df_desc.index.droplevel(level=1), inplace=True)

这导致:

print(df_desc)

>>>
                  A           B
Age         17.1527     23.9678
Age         (19.73)     (12.01)
Income       293271     12178.8
Income  (400059.27)  (14483.35)

这看起来还不太令人满意,因为索引值 AgeIncome 分别出现了两次。

这就是我想出以下内容的原因。

b) 使用 pd.DataFrame.values 创建新的 DataFrame 并手动分配索引

首先,重置索引:

df_desc = df_desc.reset_index(drop=True)

print(df_desc)

>>>
            A           B
0      17.306      11.425
1     (14.40)     (16.67)
2     88016.7     67280.4
3  (73054.44)  (54953.69)

其次,创建新的 DataFrame 并手动指定索引和列名。 请注意,我使用 df_desc.values 作为数据参数(第一个位置)。

df_new = pd.DataFrame(df_desc.values, index=["Age", "", "Income", ""], columns=["A", "B"])

print(df_new)

>>>
                 A           B
Age        27.7039     20.8031
           (13.99)     (13.92)
Income     20690.7     7370.44
        (29470.03)  (13279.10)

问题 2:对齐 LaTeX table

请注意 运行

df_new.to_latex()

确实会产生一些混乱的 str 输出:

>>> 
'\begin{tabular}{lll}\n\toprule\n{} &           A &           B \\\n\midrule\nAge    &     27.7039 &     20.8031 \\\n       &     (13.99) &     (13.92) \\\nIncome &     20690.7 &     7370.44 \\\n       &  (29470.03) &  (13279.10) \\\n\bottomrule\n\end{tabular}\n'

但是,将其包装在 print 语句中会产生所需的输出:

print(df_new.to_latex())

>>>
\begin{tabular}{lll}
\toprule
{} &           A &           B \
\midrule
Age    &     27.7039 &     20.8031 \
       &     (13.99) &     (13.92) \
Income &     20690.7 &     7370.44 \
       &  (29470.03) &  (13279.10) \
\bottomrule
\end{tabular}

此外,将 table 导出到 LaTeX 文档非常简单。

正如您自己所说,to_latex() 已经创建了一个表格,因此您只需将其写入文件,然后在您的 LaTeX 文档中使用 \input。 按照示例 here,执行以下操作:

i) 将 table 保存为文本文件

with open('mytable.tex','w') as tf:
    tf.write(df_new.to_latex())

ii) 在 LaTeX 文档中使用导出的 table

\documentclass{article}
\usepackage{booktabs}
\begin{document}
\input{mytable}
\end{document}

此处的示例假设 mytable.tex 和 LaTeX 文档位于同一文件夹中。 booktabs 包是必需的,因为 to_latex() 使用 table 规则的 booktabs 命令。

最终的 pdf 输出如下所示: