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)
这看起来还不太令人满意,因为索引值 Age 和 Income 分别出现了两次。
这就是我想出以下内容的原因。
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 输出如下所示:
这个问题涉及在 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)
这看起来还不太令人满意,因为索引值 Age 和 Income 分别出现了两次。
这就是我想出以下内容的原因。
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 输出如下所示: