diff --git a/main.pdf b/main.pdf index d008494..ea74f59 100644 Binary files a/main.pdf and b/main.pdf differ diff --git a/panel.tex b/panel.tex index 743a7fc..493eee5 100644 --- a/panel.tex +++ b/panel.tex @@ -5,8 +5,9 @@ \begin{tabularx}{\textwidth}{>{\raggedright\arraybackslash}X>{\centering\arraybackslash}X>{\centering\arraybackslash}X} - \multicolumn{3}{l}{Panel A: Men}\\ \toprule + \toprule + \multicolumn{3}{l}{Panel A: Men}\\ \toprule & ID & School\\ \midrule diff --git a/pyproject.toml b/pyproject.toml index 7971459..a71e79e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,7 @@ dependencies = [ "pandas>=2", "scipy", "unicodeit", + "narwhals", ] [project.optional-dependencies] @@ -50,6 +51,7 @@ test = [ "faker", "polars", "pyarrow", + "narwhals", ] dev = [ diff --git a/samplenotebook.ipynb b/samplenotebook.ipynb index efcefd9..64e180f 100644 --- a/samplenotebook.ipynb +++ b/samplenotebook.ipynb @@ -69,7 +69,7 @@ "type": "integer" } ], - "ref": "8f2a7b99-50f5-4e7b-b566-ca6d16cc70f2", + "ref": "0a26eadc-ffb0-4183-ba5d-704107dc2aec", "rows": [ [ "0", @@ -712,111 +712,63 @@ " \n", " \n", " A\n", - "\n", " -0.12\n", - "\n", " -0.116\n", - "\n", " 0.058\n", - "\n", " -0.058\n", - "\n", " 0.001\n", - "\n", " -0.173\n", - "\n", " -0.174\n", - "\n", " \n", " \n", " \n", - "\n", " (0.099)\n", - "\n", " (0.102)\n", - "\n", " (0.092)\n", - "\n", " (0.056)\n", - "\n", " (0.142)\n", - "\n", " (0.135)\n", - "\n", " (0.137)\n", - "\n", " \n", " \n", " B\n", - "\n", " 0.108\n", - "\n", " 5.008\n", - "\n", " 0.059\n", - "\n", " 1.725\n", - "\n", " -4.900***\n", - "\n", " 0.048\n", - "\n", " 4.949***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.102)\n", - "\n", " (0.207)\n", - "\n", " (0.105)\n", - "\n", " (0.158)\n", - "\n", " (0.231)\n", - "\n", " (0.147)\n", - "\n", " (0.232)\n", - "\n", " \n", " \n", " C\n", - "\n", " 0.062\n", - "\n", " 1.122\n", - "\n", " 1.223\n", - "\n", " 0.802\n", - "\n", " -1.060***\n", - "\n", " -1.161***\n", - "\n", " -0.101\n", - "\n", " \n", " \n", " \n", - "\n", " (0.082)\n", - "\n", " (0.106)\n", - "\n", " (0.091)\n", - "\n", " (0.062)\n", - "\n", " (0.134)\n", - "\n", " (0.123)\n", - "\n", " (0.140)\n", - "\n", " \n", " \n", " \n", @@ -937,83 +889,51 @@ " \n", " \n", " Number of Observations\n", - "\n", " 300\n", - "\n", " 300\n", - "\n", " 300\n", - "\n", " \n", " \n", " Mean\n", - "\n", " -0.06\n", - "\n", " 1.725\n", - "\n", " 0.802\n", - "\n", " \n", " \n", " Std. Dev.\n", - "\n", " 0.976\n", - "\n", " 2.745\n", - "\n", " 1.0709\n", - "\n", " \n", " \n", " Min.\n", - "\n", " -2.782\n", - "\n", " -2.535\n", - "\n", " -1.480\n", - "\n", " \n", " \n", " ░\n", - "\n", " -0.709\n", - "\n", " -0.221\n", - "\n", " 0.094\n", - "\n", " \n", " \n", " ▒\n", - "\n", " -0.050\n", - "\n", " 0.814\n", - "\n", " 0.736\n", - "\n", " \n", " \n", " ▓\n", - "\n", " 0.543\n", - "\n", " 3.703\n", - "\n", " 1.501\n", - "\n", " \n", " \n", " Max.\n", - "\n", " 2.82\n", - "\n", " 10.80\n", - "\n", " 3.99\n", - "\n", " \n", " \n", " \n", @@ -1137,33 +1057,23 @@ " \n", " \n", " Unique Sites\n", - "\n", " 10,000\n", - "\n", " \n", " \n", " Unique IPs\n", - "\n", " 20,000\n", - "\n", " \n", " \n", " IPs in EU\n", - "\n", " 5,000\n", - "\n", " \n", " \n", " IPs in US\n", - "\n", " 3,000\n", - "\n", " \n", " \n", " IPs outside EU\n", - "\n", " 5,000\n", - "\n", " \n", " \n", " \n", @@ -1296,20 +1206,20 @@ "text": [ "Note: Standard errors assume samples are drawn independently.\n", "\n", - " Differences in means \n", - "-----------------------------------------------------------------------------------------------------------------------\n", - "+ Means Differences +\n", - "+ ---------------------------------------------- ---------------------------------------------- +\n", - "+ X Y Z Overall Mean X - Y X - Z Y - Z +\n", - "+ N=100 N=100 N=100 N=300 +\n", - "+=====================================================================================================================+\n", - "+ A -0.12 -0.116 0.058 -0.058 0.001 -0.173 -0.174 +\n", - "+ (0.099) (0.102) (0.092) (0.056) (0.142) (0.135) (0.137) +\n", - "+ B 0.108 5.008 0.059 1.725 -4.900*** 0.048 4.949*** +\n", - "+ (0.102) (0.207) (0.105) (0.158) (0.231) (0.147) (0.232) +\n", - "+ C 0.062 1.122 1.223 0.802 -1.060*** -1.161*** -0.101 +\n", - "+ (0.082) (0.106) (0.091) (0.062) (0.134) (0.123) (0.140) +\n", - "-----------------------------------------------------------------------------------------------------------------------\n", + " Differences in means \n", + "=====================================================================================================================\n", + " Means Differences \n", + " ---------------------------------------------- ---------------------------------------------- \n", + " X Y Z Overall Mean X - Y X - Z Y - Z \n", + " N=100 N=100 N=100 N=300 \n", + "---------------------------------------------------------------------------------------------------------------------\n", + " A -0.12 -0.116 0.058 -0.058 0.001 -0.173 -0.174 \n", + " (0.099) (0.102) (0.092) (0.056) (0.142) (0.135) (0.137) \n", + " B 0.108 5.008 0.059 1.725 -4.900*** 0.048 4.949*** \n", + " (0.102) (0.207) (0.105) (0.158) (0.231) (0.147) (0.232) \n", + " C 0.062 1.122 1.223 0.802 -1.060*** -1.161*** -0.101 \n", + " (0.082) (0.106) (0.091) (0.062) (0.134) (0.123) (0.140) \n", + "---------------------------------------------------------------------------------------------------------------------\n", "* p< 0.1, ** p< 0.05, *** p< 0.01 \n" ] } @@ -1339,13 +1249,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "--------------------------------------------------\n", - "+ Unique Sites 10,000 +\n", - "+ Unique IPs 20,000 +\n", - "+ IPs in EU 5,000 +\n", - "+ IPs in US 3,000 +\n", - "+ IPs outside EU 5,000 +\n", - "--------------------------------------------------\n" + "====================================\n", + " Unique Sites 10,000 \n", + " Unique IPs 20,000 \n", + " IPs in EU 5,000 \n", + " IPs in US 3,000 \n", + " IPs outside EU 5,000 \n", + "------------------------------------\n" ] } ], @@ -1393,83 +1303,51 @@ " \n", " \n", " Number of Observations\n", - "\n", " 300\n", - "\n", " 300\n", - "\n", " 300\n", - "\n", " \n", " \n", " Mean\n", - "\n", " -0.06\n", - "\n", " 1.725\n", - "\n", " 0.802\n", - "\n", " \n", " \n", " Std. Dev.\n", - "\n", " 0.976\n", - "\n", " 2.745\n", - "\n", " 1.0709\n", - "\n", " \n", " \n", " Min.\n", - "\n", " -2.782\n", - "\n", " -2.535\n", - "\n", " -1.480\n", - "\n", " \n", " \n", " ░\n", - "\n", " -0.709\n", - "\n", " -0.221\n", - "\n", " 0.094\n", - "\n", " \n", " \n", " ▒\n", - "\n", " -0.050\n", - "\n", " 0.814\n", - "\n", " 0.736\n", - "\n", " \n", " \n", " ▓\n", - "\n", " 0.543\n", - "\n", " 3.703\n", - "\n", " 1.501\n", - "\n", " \n", " \n", " Max.\n", - "\n", " 2.82\n", - "\n", " 10.80\n", - "\n", " 3.99\n", - "\n", " \n", " \n", " \n", @@ -1496,28 +1374,28 @@ ], "text/plain": [ "\n", - " Summary Table \n", - "----------------------------------------------------------------------------------\n", - "+ First Second +\n", - "+ -------------- ------------------------------ +\n", - "+ a B C +\n", - "+ Example Yes No Yes +\n", - "+================================================================================+\n", - "+ Number of Observations 300 300 300 +\n", - "+ Mean -0.06 1.725 0.802 +\n", - "+ Std. Dev. 0.976 2.745 1.0709 +\n", - "+ Min. -2.782 -2.535 -1.480 +\n", - "+ ░ -0.709 -0.221 0.094 +\n", - "+ ▒ -0.050 0.814 0.736 +\n", - "+ ▓ 0.543 3.703 1.501 +\n", - "+ Max. 2.82 10.80 3.99 +\n", - "+ No Yes No +\n", - "----------------------------------------------------------------------------------\n", - "+ Lowest Low A Low B Low C +\n", - "----------------------------------------------------------------------------------\n", - " The default note aligns over here.\n", - " But you can move it to the middle! \n", - "Or over here! " + " Summary Table \n", + "========================================================\n", + " First Second \n", + " -------- ------------------ \n", + " a B C \n", + " Example Yes No Yes \n", + "--------------------------------------------------------\n", + " Number of Observations 300 300 300 \n", + " Mean -0.06 1.725 0.802 \n", + " Std. Dev. 0.976 2.745 1.0709 \n", + " Min. -2.782 -2.535 -1.480 \n", + " ░ -0.709 -0.221 0.094 \n", + " ▒ -0.050 0.814 0.736 \n", + " ▓ 0.543 3.703 1.501 \n", + " Max. 2.82 10.80 3.99 \n", + " No Yes No \n", + "--------------------------------------------------------\n", + " Lowest Low A Low B Low C \n", + "--------------------------------------------------------\n", + " The default note aligns over here.\n", + " But you can move it to the middle! \n", + "Or over here! " ] }, "execution_count": 14, @@ -1539,28 +1417,28 @@ "output_type": "stream", "text": [ "\n", - " Summary Table \n", - "----------------------------------------------------------------------------------\n", - "+ First Second +\n", - "+ -------------- ------------------------------ +\n", - "+ a B C +\n", - "+ Example Yes No Yes +\n", - "+================================================================================+\n", - "+ Number of Observations 300 300 300 +\n", - "+ Mean -0.06 1.725 0.802 +\n", - "+ Std. Dev. 0.976 2.745 1.0709 +\n", - "+ Min. -2.782 -2.535 -1.480 +\n", - "+ ░ -0.709 -0.221 0.094 +\n", - "+ ▒ -0.050 0.814 0.736 +\n", - "+ ▓ 0.543 3.703 1.501 +\n", - "+ Max. 2.82 10.80 3.99 +\n", - "+ No Yes No +\n", - "----------------------------------------------------------------------------------\n", - "+ Lowest Low A Low B Low C +\n", - "----------------------------------------------------------------------------------\n", - " The default note aligns over here.\n", - " But you can move it to the middle! \n", - "Or over here! \n" + " Summary Table \n", + "========================================================\n", + " First Second \n", + " -------- ------------------ \n", + " a B C \n", + " Example Yes No Yes \n", + "--------------------------------------------------------\n", + " Number of Observations 300 300 300 \n", + " Mean -0.06 1.725 0.802 \n", + " Std. Dev. 0.976 2.745 1.0709 \n", + " Min. -2.782 -2.535 -1.480 \n", + " ░ -0.709 -0.221 0.094 \n", + " ▒ -0.050 0.814 0.736 \n", + " ▓ 0.543 3.703 1.501 \n", + " Max. 2.82 10.80 3.99 \n", + " No Yes No \n", + "--------------------------------------------------------\n", + " Lowest Low A Low B Low C \n", + "--------------------------------------------------------\n", + " The default note aligns over here.\n", + " But you can move it to the middle! \n", + "Or over here! \n" ] } ], @@ -1635,106 +1513,66 @@ " \n", " \n", " Intercept\n", - "\n", " \n", - "\n", " -0.025\n", - "\n", " -0.284***\n", - "\n", " \n", " \n", " \n", - "\n", " \n", - "\n", " (0.076)\n", - "\n", " (0.100)\n", - "\n", " \n", " \n", " B\n", - "\n", " -0.029\n", - "\n", " -0.026\n", - "\n", " 0.070**\n", - "\n", " \n", " \n", " \n", - "\n", " (0.019)\n", - "\n", " (0.021)\n", - "\n", " (0.028)\n", - "\n", " \n", " \n", " C\n", - "\n", " 0.006\n", - "\n", " 0.015\n", - "\n", " 0.123*\n", - "\n", " \n", " \n", " \n", - "\n", " (0.047)\n", - "\n", " (0.054)\n", - "\n", " (0.070)\n", - "\n", " \n", " \n", " \n", " \n", " \n", " Observations\n", - "\n", " 300\n", - "\n", " 300\n", - "\n", " 300\n", - "\n", " \n", " \n", " R2\n", - "\n", " 0.008\n", - "\n", " 0.005\n", - "\n", " \n", - "\n", " \n", " \n", " Pseudo R2\n", - "\n", " \n", - "\n", " \n", - "\n", " 0.030\n", - "\n", " \n", " \n", " F Statistic\n", - "\n", " 1.255\n", - "\n", " 0.778\n", - "\n", " \n", - "\n", " \n", " \n", " \n", @@ -1744,22 +1582,22 @@ "" ], "text/plain": [ - "------------------------------------------------------------------------------------------\n", - "+ (1) (2) (3) +\n", - "+========================================================================================+\n", - "+ Intercept -0.025 -0.284*** +\n", - "+ (0.076) (0.100) +\n", - "+ B -0.029 -0.026 0.070** +\n", - "+ (0.019) (0.021) (0.028) +\n", - "+ C 0.006 0.015 0.123* +\n", - "+ (0.047) (0.054) (0.070) +\n", - "==========================================================================================\n", - "+ Observations 300 300 300 +\n", - "+ R² 0.008 0.005 +\n", - "+ Pseudo R² 0.030 +\n", - "+ F Statistic 1.255 0.778 +\n", - "------------------------------------------------------------------------------------------\n", - "*p<0.1, **p<0.05, ***p<0.01 " + "================================================================\n", + " (1) (2) (3) \n", + "----------------------------------------------------------------\n", + " Intercept -0.025 -0.284*** \n", + " (0.076) (0.100) \n", + " B -0.029 -0.026 0.070** \n", + " (0.019) (0.021) (0.028) \n", + " C 0.006 0.015 0.123* \n", + " (0.047) (0.054) (0.070) \n", + "----------------------------------------------------------------\n", + " Observations 300 300 300 \n", + " R² 0.008 0.005 \n", + " Pseudo R² 0.030 \n", + " F Statistic 1.255 0.778 \n", + "----------------------------------------------------------------\n", + "*p<0.1, **p<0.05, ***p<0.01 " ] }, "execution_count": 18, @@ -1809,96 +1647,60 @@ " \n", " \n", " Intercept\n", - "\n", " -0.185\n", - "\n", " 10.237***\n", - "\n", " 0.441\n", - "\n", " \n", " \n", " \n", - "\n", " (0.185)\n", - "\n", " (0.275)\n", - "\n", " (0.445)\n", - "\n", " \n", " \n", " Father Education\n", - "\n", " \n", - "\n", " 0.269***\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " \n", - "\n", " (0.029)\n", - "\n", " \n", - "\n", " \n", " \n", " Education\n", - "\n", " 0.109***\n", - "\n", " \n", - "\n", " 0.059*\n", - "\n", " \n", " \n", " \n", - "\n", " (0.014)\n", - "\n", " \n", - "\n", " (0.035)\n", - "\n", " \n", " \n", " \n", " \n", " \n", " Observations\n", - "\n", " 428\n", - "\n", " 428\n", - "\n", " 428\n", - "\n", " \n", " \n", " R2\n", - "\n", " 0.118\n", - "\n", " 0.173\n", - "\n", " 0.093\n", - "\n", " \n", " \n", " F Statistic\n", - "\n", " 57.196***\n", - "\n", " 89.258***\n", - "\n", " 2.849*\n", - "\n", " \n", " \n", " \n", @@ -1908,24 +1710,24 @@ "" ], "text/plain": [ - "----------------------------------------------------------------------------------------------\n", - "+ OLS 2SLS +\n", - "+ -------------------- ------------------------------------------ +\n", - "+ First Stage Second Stage +\n", - "+ (1) (2) (3) +\n", - "+============================================================================================+\n", - "+ Intercept -0.185 10.237*** 0.441 +\n", - "+ (0.185) (0.275) (0.445) +\n", - "+ Father Education 0.269*** +\n", - "+ (0.029) +\n", - "+ Education 0.109*** 0.059* +\n", - "+ (0.014) (0.035) +\n", - "==============================================================================================\n", - "+ Observations 428 428 428 +\n", - "+ R² 0.118 0.173 0.093 +\n", - "+ F Statistic 57.196*** 89.258*** 2.849* +\n", - "----------------------------------------------------------------------------------------------\n", - "*p<0.1, **p<0.05, ***p<0.01 " + "====================================================================\n", + " OLS 2SLS \n", + " -------------- ------------------------------ \n", + " First Stage Second Stage \n", + " (1) (2) (3) \n", + "--------------------------------------------------------------------\n", + " Intercept -0.185 10.237*** 0.441 \n", + " (0.185) (0.275) (0.445) \n", + " Father Education 0.269*** \n", + " (0.029) \n", + " Education 0.109*** 0.059* \n", + " (0.014) (0.035) \n", + "--------------------------------------------------------------------\n", + " Observations 428 428 428 \n", + " R² 0.118 0.173 0.093 \n", + " F Statistic 57.196*** 89.258*** 2.849* \n", + "--------------------------------------------------------------------\n", + "*p<0.1, **p<0.05, ***p<0.01 " ] }, "execution_count": 19, @@ -1974,23 +1776,23 @@ "name": "stdout", "output_type": "stream", "text": [ - "----------------------------------------------------------------------\n", - "+ OLS 2SLS +\n", - "+ -------------- ------------------------------ +\n", - "+ First Stage Second Stage +\n", - "+ (1) (2) (3) +\n", - "+====================================================================+\n", - "+ Intercept -0.185 10.237*** 0.441 +\n", - "+ (0.185) (0.275) (0.445) +\n", - "+ Father Education 0.269*** +\n", - "+ (0.029) +\n", - "+ Education 0.109*** 0.059* +\n", - "+ (0.014) (0.035) +\n", - "======================================================================\n", - "+ Observations 428 428 428 +\n", - "+ R² 0.118 0.173 0.093 +\n", - "+ F Statistic 57.196*** 89.258*** 2.849* +\n", - "----------------------------------------------------------------------\n", + "====================================================================\n", + " OLS 2SLS \n", + " -------------- ------------------------------ \n", + " First Stage Second Stage \n", + " (1) (2) (3) \n", + "--------------------------------------------------------------------\n", + " Intercept -0.185 10.237*** 0.441 \n", + " (0.185) (0.275) (0.445) \n", + " Father Education 0.269*** \n", + " (0.029) \n", + " Education 0.109*** 0.059* \n", + " (0.014) (0.035) \n", + "--------------------------------------------------------------------\n", + " Observations 428 428 428 \n", + " R² 0.118 0.173 0.093 \n", + " F Statistic 57.196*** 89.258*** 2.849* \n", + "--------------------------------------------------------------------\n", "*p<0.1, **p<0.05, ***p<0.01 \n" ] } @@ -2026,29 +1828,29 @@ "name": "stdout", "output_type": "stream", "text": [ - "------------------------------------------------------------------------\n", - "+ Dependent Variable: Log(Wage) +\n", - "+ ---------------------------------------------- +\n", - "+ (1) (2) (3) +\n", - "+======================================================================+\n", - "+ Intercept 0.092 0.023 1.871*** +\n", - "+ (0.078) (0.151) (0.038) +\n", - "+ Experience 0.067*** 0.106*** +\n", - "+ (0.014) (0.015) +\n", - "+ Experience Squared -0.002*** -0.005*** -0.005*** +\n", - "+ (0.001) (0.001) (0.001) +\n", - "+ Union 0.182*** 0.106*** 0.080*** +\n", - "+ (0.017) (0.018) (0.019) +\n", - "+ Married 0.108*** 0.064*** 0.047** +\n", - "+ (0.016) (0.017) (0.018) +\n", - "+ Black -0.139*** -0.139*** +\n", - "+ (0.024) (0.048) +\n", - "========================================================================\n", - "+ Observations 4,360 4,360 4,360 +\n", - "+ N. Groups 545 545 545 +\n", - "+ R² 0.189 0.181 0.022 +\n", - "+ F Statistic 72.459*** 68.409*** 27.959*** +\n", - "------------------------------------------------------------------------\n", + "======================================================================\n", + " Dependent Variable: Log(Wage) \n", + " ---------------------------------------------- \n", + " (1) (2) (3) \n", + "----------------------------------------------------------------------\n", + " Intercept 0.092 0.023 1.871*** \n", + " (0.078) (0.151) (0.038) \n", + " Experience 0.067*** 0.106*** \n", + " (0.014) (0.015) \n", + " Experience Squared -0.002*** -0.005*** -0.005*** \n", + " (0.001) (0.001) (0.001) \n", + " Union 0.182*** 0.106*** 0.080*** \n", + " (0.017) (0.018) (0.019) \n", + " Married 0.108*** 0.064*** 0.047** \n", + " (0.016) (0.017) (0.018) \n", + " Black -0.139*** -0.139*** \n", + " (0.024) (0.048) \n", + "----------------------------------------------------------------------\n", + " Observations 4,360 4,360 4,360 \n", + " N. Groups 545 545 545 \n", + " R² 0.189 0.181 0.022 \n", + " F Statistic 72.459*** 68.409*** 27.959*** \n", + "----------------------------------------------------------------------\n", "*p<0.1, **p<0.05, ***p<0.01 \n" ] } @@ -2167,166 +1969,102 @@ " \n", " \n", " α\n", - "\n", " 0.092\n", - "\n", " 0.023\n", - "\n", " 1.871***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.078)\n", - "\n", " (0.151)\n", - "\n", " (0.038)\n", - "\n", " \n", " \n", " Experience\n", - "\n", " 0.067***\n", - "\n", " 0.106***\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.014)\n", - "\n", " (0.015)\n", - "\n", " \n", - "\n", " \n", " \n", " Experience²\n", - "\n", " -0.002***\n", - "\n", " -0.005***\n", - "\n", " -0.005***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.001)\n", - "\n", " (0.001)\n", - "\n", " (0.001)\n", - "\n", " \n", " \n", " Union\n", - "\n", " 0.182***\n", - "\n", " 0.106***\n", - "\n", " 0.080***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.017)\n", - "\n", " (0.018)\n", - "\n", " (0.019)\n", - "\n", " \n", " \n", " Married\n", - "\n", " 0.108***\n", - "\n", " 0.064***\n", - "\n", " 0.047**\n", - "\n", " \n", " \n", " \n", - "\n", " (0.016)\n", - "\n", " (0.017)\n", - "\n", " (0.018)\n", - "\n", " \n", " \n", " Black\n", - "\n", " -0.139***\n", - "\n", " -0.139***\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.024)\n", - "\n", " (0.048)\n", - "\n", " \n", - "\n", " \n", " \n", " \n", " \n", " \n", " Observations\n", - "\n", " 4,360\n", - "\n", " 4,360\n", - "\n", " 4,360\n", - "\n", " \n", " \n", " N. Groups\n", - "\n", " 545\n", - "\n", " 545\n", - "\n", " 545\n", - "\n", " \n", " \n", " R2\n", - "\n", " 0.189\n", - "\n", " 0.181\n", - "\n", " 0.022\n", - "\n", " \n", " \n", " F Statistic\n", - "\n", " 72.459***\n", - "\n", " 68.409***\n", - "\n", " 27.959***\n", - "\n", " \n", " \n", " \n", @@ -2336,29 +2074,29 @@ "" ], "text/plain": [ - "------------------------------------------------------------------\n", - "+ Dependent Variable: Log(Wage) +\n", - "+ ---------------------------------------------- +\n", - "+ (1) (2) (3) +\n", - "+================================================================+\n", - "+ α 0.092 0.023 1.871*** +\n", - "+ (0.078) (0.151) (0.038) +\n", - "+ Experience 0.067*** 0.106*** +\n", - "+ (0.014) (0.015) +\n", - "+ Experience² -0.002*** -0.005*** -0.005*** +\n", - "+ (0.001) (0.001) (0.001) +\n", - "+ Union 0.182*** 0.106*** 0.080*** +\n", - "+ (0.017) (0.018) (0.019) +\n", - "+ Married 0.108*** 0.064*** 0.047** +\n", - "+ (0.016) (0.017) (0.018) +\n", - "+ Black -0.139*** -0.139*** +\n", - "+ (0.024) (0.048) +\n", - "==================================================================\n", - "+ Observations 4,360 4,360 4,360 +\n", - "+ N. Groups 545 545 545 +\n", - "+ R² 0.189 0.181 0.022 +\n", - "+ F Statistic 72.459*** 68.409*** 27.959*** +\n", - "------------------------------------------------------------------\n", + "================================================================\n", + " Dependent Variable: Log(Wage) \n", + " ---------------------------------------------- \n", + " (1) (2) (3) \n", + "----------------------------------------------------------------\n", + " α 0.092 0.023 1.871*** \n", + " (0.078) (0.151) (0.038) \n", + " Experience 0.067*** 0.106*** \n", + " (0.014) (0.015) \n", + " Experience² -0.002*** -0.005*** -0.005*** \n", + " (0.001) (0.001) (0.001) \n", + " Union 0.182*** 0.106*** 0.080*** \n", + " (0.017) (0.018) (0.019) \n", + " Married 0.108*** 0.064*** 0.047** \n", + " (0.016) (0.017) (0.018) \n", + " Black -0.139*** -0.139*** \n", + " (0.024) (0.048) \n", + "----------------------------------------------------------------\n", + " Observations 4,360 4,360 4,360 \n", + " N. Groups 545 545 545 \n", + " R² 0.189 0.181 0.022 \n", + " F Statistic 72.459*** 68.409*** 27.959*** \n", + "----------------------------------------------------------------\n", "*p<0.1, **p<0.05, ***p<0.01 " ] }, @@ -2396,29 +2134,29 @@ "name": "stdout", "output_type": "stream", "text": [ - "------------------------------------------------------------------\n", - "+ Dependent Variable: Log(Wage) +\n", - "+ ---------------------------------------------- +\n", - "+ (1) (2) (3) +\n", - "+================================================================+\n", - "+ α 0.092 0.023 1.871*** +\n", - "+ (0.078) (0.151) (0.038) +\n", - "+ Experience 0.067*** 0.106*** +\n", - "+ (0.014) (0.015) +\n", - "+ Experience² -0.002*** -0.005*** -0.005*** +\n", - "+ (0.001) (0.001) (0.001) +\n", - "+ Union 0.182*** 0.106*** 0.080*** +\n", - "+ (0.017) (0.018) (0.019) +\n", - "+ Married 0.108*** 0.064*** 0.047** +\n", - "+ (0.016) (0.017) (0.018) +\n", - "+ Black -0.139*** -0.139*** +\n", - "+ (0.024) (0.048) +\n", - "==================================================================\n", - "+ Observations 4,360 4,360 4,360 +\n", - "+ N. Groups 545 545 545 +\n", - "+ R² 0.189 0.181 0.022 +\n", - "+ F Statistic 72.459*** 68.409*** 27.959*** +\n", - "------------------------------------------------------------------\n", + "================================================================\n", + " Dependent Variable: Log(Wage) \n", + " ---------------------------------------------- \n", + " (1) (2) (3) \n", + "----------------------------------------------------------------\n", + " α 0.092 0.023 1.871*** \n", + " (0.078) (0.151) (0.038) \n", + " Experience 0.067*** 0.106*** \n", + " (0.014) (0.015) \n", + " Experience² -0.002*** -0.005*** -0.005*** \n", + " (0.001) (0.001) (0.001) \n", + " Union 0.182*** 0.106*** 0.080*** \n", + " (0.017) (0.018) (0.019) \n", + " Married 0.108*** 0.064*** 0.047** \n", + " (0.016) (0.017) (0.018) \n", + " Black -0.139*** -0.139*** \n", + " (0.024) (0.048) \n", + "----------------------------------------------------------------\n", + " Observations 4,360 4,360 4,360 \n", + " N. Groups 545 545 545 \n", + " R² 0.189 0.181 0.022 \n", + " F Statistic 72.459*** 68.409*** 27.959*** \n", + "----------------------------------------------------------------\n", "*p<0.1, **p<0.05, ***p<0.01 \n" ] } @@ -2458,166 +2196,102 @@ " \n", " \n", " α\n", - "\n", " 0.092\n", - "\n", " 0.023\n", - "\n", " 1.871***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.078)\n", - "\n", " (0.151)\n", - "\n", " (0.038)\n", - "\n", " \n", " \n", " Experience\n", - "\n", " 0.067***\n", - "\n", " 0.106***\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.014)\n", - "\n", " (0.015)\n", - "\n", " \n", - "\n", " \n", " \n", " Experience²\n", - "\n", " -0.002***\n", - "\n", " -0.005***\n", - "\n", " -0.005***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.001)\n", - "\n", " (0.001)\n", - "\n", " (0.001)\n", - "\n", " \n", " \n", " Union\n", - "\n", " 0.182***\n", - "\n", " 0.106***\n", - "\n", " 0.080***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.017)\n", - "\n", " (0.018)\n", - "\n", " (0.019)\n", - "\n", " \n", " \n", " Married\n", - "\n", " 0.108***\n", - "\n", " 0.064***\n", - "\n", " 0.047**\n", - "\n", " \n", " \n", " \n", - "\n", " (0.016)\n", - "\n", " (0.017)\n", - "\n", " (0.018)\n", - "\n", " \n", " \n", " Black\n", - "\n", " -0.139***\n", - "\n", " -0.139***\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.024)\n", - "\n", " (0.048)\n", - "\n", " \n", - "\n", " \n", " \n", " \n", " \n", " \n", " Observations\n", - "\n", " 4,360\n", - "\n", " 4,360\n", - "\n", " 4,360\n", - "\n", " \n", " \n", " N. Groups\n", - "\n", " 545\n", - "\n", " 545\n", - "\n", " 545\n", - "\n", " \n", " \n", " R2\n", - "\n", " 0.189\n", - "\n", " 0.181\n", - "\n", " 0.022\n", - "\n", " \n", " \n", " F Statistic\n", - "\n", " 72.459***\n", - "\n", " 68.409***\n", - "\n", " 27.959***\n", - "\n", " \n", " \n", " \n", @@ -2627,29 +2301,29 @@ "" ], "text/plain": [ - "------------------------------------------------------------------\n", - "+ Dependent Variable: Log(Wage) +\n", - "+ ---------------------------------------------- +\n", - "+ (1) (2) (3) +\n", - "+================================================================+\n", - "+ α 0.092 0.023 1.871*** +\n", - "+ (0.078) (0.151) (0.038) +\n", - "+ Experience 0.067*** 0.106*** +\n", - "+ (0.014) (0.015) +\n", - "+ Experience² -0.002*** -0.005*** -0.005*** +\n", - "+ (0.001) (0.001) (0.001) +\n", - "+ Union 0.182*** 0.106*** 0.080*** +\n", - "+ (0.017) (0.018) (0.019) +\n", - "+ Married 0.108*** 0.064*** 0.047** +\n", - "+ (0.016) (0.017) (0.018) +\n", - "+ Black -0.139*** -0.139*** +\n", - "+ (0.024) (0.048) +\n", - "==================================================================\n", - "+ Observations 4,360 4,360 4,360 +\n", - "+ N. Groups 545 545 545 +\n", - "+ R² 0.189 0.181 0.022 +\n", - "+ F Statistic 72.459*** 68.409*** 27.959*** +\n", - "------------------------------------------------------------------\n", + "================================================================\n", + " Dependent Variable: Log(Wage) \n", + " ---------------------------------------------- \n", + " (1) (2) (3) \n", + "----------------------------------------------------------------\n", + " α 0.092 0.023 1.871*** \n", + " (0.078) (0.151) (0.038) \n", + " Experience 0.067*** 0.106*** \n", + " (0.014) (0.015) \n", + " Experience² -0.002*** -0.005*** -0.005*** \n", + " (0.001) (0.001) (0.001) \n", + " Union 0.182*** 0.106*** 0.080*** \n", + " (0.017) (0.018) (0.019) \n", + " Married 0.108*** 0.064*** 0.047** \n", + " (0.016) (0.017) (0.018) \n", + " Black -0.139*** -0.139*** \n", + " (0.024) (0.048) \n", + "----------------------------------------------------------------\n", + " Observations 4,360 4,360 4,360 \n", + " N. Groups 545 545 545 \n", + " R² 0.189 0.181 0.022 \n", + " F Statistic 72.459*** 68.409*** 27.959*** \n", + "----------------------------------------------------------------\n", "*p<0.1, **p<0.05, ***p<0.01 " ] }, @@ -2752,346 +2426,210 @@ " \n", " \n", " black\n", - "\n", " -0.139***\n", - "\n", " -0.139***\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.024)\n", - "\n", " (0.048)\n", - "\n", " \n", - "\n", " \n", " \n", " const\n", - "\n", " 0.092\n", - "\n", " 0.023\n", - "\n", " 1.871***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.078)\n", - "\n", " (0.151)\n", - "\n", " (0.038)\n", - "\n", " \n", " \n", " educ\n", - "\n", " 0.091***\n", - "\n", " 0.092***\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.005)\n", - "\n", " (0.011)\n", - "\n", " \n", - "\n", " \n", " \n", " exper\n", - "\n", " 0.067***\n", - "\n", " 0.106***\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.014)\n", - "\n", " (0.015)\n", - "\n", " \n", - "\n", " \n", " \n", " expersq\n", - "\n", " -0.002***\n", - "\n", " -0.005***\n", - "\n", " -0.005***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.001)\n", - "\n", " (0.001)\n", - "\n", " (0.001)\n", - "\n", " \n", " \n", " hisp\n", - "\n", " 0.016\n", - "\n", " 0.022\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.021)\n", - "\n", " (0.043)\n", - "\n", " \n", - "\n", " \n", " \n", " married\n", - "\n", " 0.108***\n", - "\n", " 0.064***\n", - "\n", " 0.047**\n", - "\n", " \n", " \n", " \n", - "\n", " (0.016)\n", - "\n", " (0.017)\n", - "\n", " (0.018)\n", - "\n", " \n", " \n", " union\n", - "\n", " 0.182***\n", - "\n", " 0.106***\n", - "\n", " 0.080***\n", - "\n", " \n", " \n", " \n", - "\n", " (0.017)\n", - "\n", " (0.018)\n", - "\n", " (0.019)\n", - "\n", " \n", " \n", " year.1981\n", - "\n", " 0.058*\n", - "\n", " 0.040\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.030)\n", - "\n", " (0.025)\n", - "\n", " \n", - "\n", " \n", " \n", " year.1982\n", - "\n", " 0.063*\n", - "\n", " 0.031\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.033)\n", - "\n", " (0.032)\n", - "\n", " \n", - "\n", " \n", " \n", " year.1983\n", - "\n", " 0.062*\n", - "\n", " 0.020\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.037)\n", - "\n", " (0.042)\n", - "\n", " \n", - "\n", " \n", " \n", " year.1984\n", - "\n", " 0.090**\n", - "\n", " 0.043\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.040)\n", - "\n", " (0.052)\n", - "\n", " \n", - "\n", " \n", " \n", " year.1985\n", - "\n", " 0.109**\n", - "\n", " 0.058\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.043)\n", - "\n", " (0.061)\n", - "\n", " \n", - "\n", " \n", " \n", " year.1986\n", - "\n", " 0.142***\n", - "\n", " 0.092\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.046)\n", - "\n", " (0.072)\n", - "\n", " \n", - "\n", " \n", " \n", " year.1987\n", - "\n", " 0.174***\n", - "\n", " 0.135*\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.049)\n", - "\n", " (0.082)\n", - "\n", " \n", - "\n", " \n", " \n", " \n", " \n", " \n", " Observations\n", - "\n", " 4,360\n", - "\n", " 4,360\n", - "\n", " 4,360\n", - "\n", " \n", " \n", " N. Groups\n", - "\n", " 545\n", - "\n", " 545\n", - "\n", " 545\n", - "\n", " \n", " \n", " R2\n", - "\n", " 0.189\n", - "\n", " 0.181\n", - "\n", " 0.022\n", - "\n", " \n", " \n", " F Statistic\n", - "\n", " 72.459***\n", - "\n", " 68.409***\n", - "\n", " 27.959***\n", - "\n", " \n", " \n", " \n", @@ -3101,45 +2639,45 @@ "" ], "text/plain": [ - "------------------------------------------------------------------\n", - "+ (1) (2) (3) +\n", - "+================================================================+\n", - "+ black -0.139*** -0.139*** +\n", - "+ (0.024) (0.048) +\n", - "+ const 0.092 0.023 1.871*** +\n", - "+ (0.078) (0.151) (0.038) +\n", - "+ educ 0.091*** 0.092*** +\n", - "+ (0.005) (0.011) +\n", - "+ exper 0.067*** 0.106*** +\n", - "+ (0.014) (0.015) +\n", - "+ expersq -0.002*** -0.005*** -0.005*** +\n", - "+ (0.001) (0.001) (0.001) +\n", - "+ hisp 0.016 0.022 +\n", - "+ (0.021) (0.043) +\n", - "+ married 0.108*** 0.064*** 0.047** +\n", - "+ (0.016) (0.017) (0.018) +\n", - "+ union 0.182*** 0.106*** 0.080*** +\n", - "+ (0.017) (0.018) (0.019) +\n", - "+ year.1981 0.058* 0.040 +\n", - "+ (0.030) (0.025) +\n", - "+ year.1982 0.063* 0.031 +\n", - "+ (0.033) (0.032) +\n", - "+ year.1983 0.062* 0.020 +\n", - "+ (0.037) (0.042) +\n", - "+ year.1984 0.090** 0.043 +\n", - "+ (0.040) (0.052) +\n", - "+ year.1985 0.109** 0.058 +\n", - "+ (0.043) (0.061) +\n", - "+ year.1986 0.142*** 0.092 +\n", - "+ (0.046) (0.072) +\n", - "+ year.1987 0.174*** 0.135* +\n", - "+ (0.049) (0.082) +\n", - "==================================================================\n", - "+ Observations 4,360 4,360 4,360 +\n", - "+ N. Groups 545 545 545 +\n", - "+ R² 0.189 0.181 0.022 +\n", - "+ F Statistic 72.459*** 68.409*** 27.959*** +\n", - "------------------------------------------------------------------\n", + "================================================================\n", + " (1) (2) (3) \n", + "----------------------------------------------------------------\n", + " black -0.139*** -0.139*** \n", + " (0.024) (0.048) \n", + " const 0.092 0.023 1.871*** \n", + " (0.078) (0.151) (0.038) \n", + " educ 0.091*** 0.092*** \n", + " (0.005) (0.011) \n", + " exper 0.067*** 0.106*** \n", + " (0.014) (0.015) \n", + " expersq -0.002*** -0.005*** -0.005*** \n", + " (0.001) (0.001) (0.001) \n", + " hisp 0.016 0.022 \n", + " (0.021) (0.043) \n", + " married 0.108*** 0.064*** 0.047** \n", + " (0.016) (0.017) (0.018) \n", + " union 0.182*** 0.106*** 0.080*** \n", + " (0.017) (0.018) (0.019) \n", + " year.1981 0.058* 0.040 \n", + " (0.030) (0.025) \n", + " year.1982 0.063* 0.031 \n", + " (0.033) (0.032) \n", + " year.1983 0.062* 0.020 \n", + " (0.037) (0.042) \n", + " year.1984 0.090** 0.043 \n", + " (0.040) (0.052) \n", + " year.1985 0.109** 0.058 \n", + " (0.043) (0.061) \n", + " year.1986 0.142*** 0.092 \n", + " (0.046) (0.072) \n", + " year.1987 0.174*** 0.135* \n", + " (0.049) (0.082) \n", + "----------------------------------------------------------------\n", + " Observations 4,360 4,360 4,360 \n", + " N. Groups 545 545 545 \n", + " R² 0.189 0.181 0.022 \n", + " F Statistic 72.459*** 68.409*** 27.959*** \n", + "----------------------------------------------------------------\n", "*p<0.1, **p<0.05, ***p<0.01 " ] }, @@ -3192,26 +2730,27 @@ "name": "stdout", "output_type": "stream", "text": [ - "Panel A) Men \n", - "========================================\n", - "+ ID School +\n", - "+--------------------------------------+\n", - "+ Matthew Ortiz 1234 Texas +\n", - "+ Michael Costa 6789 UVA +\n", - "+ Samuel Johnson 1023 UMBC +\n", - "+ Dakota Snyder 5810 UGA +\n", - "+ Scott Mills 9182 Rice +\n", - "----------------------------------------\n", - "Panel B) Women \n", - "========================================================\n", - "+ ID School +\n", - "+------------------------------------------------------+\n", - "+ Erin Anderson 9183 Wake Forrest +\n", - "+ Michelle Zimmerman 5734 Emory +\n", - "+ Danielle King 1290 Texas +\n", - "+ Shannon Nelson 4743 UVA +\n", - "+ Stephanie Booth 8912 Columbia +\n", - "--------------------------------------------------------\n", + "======================================================\n", + "Panel A) Men \n", + "------------------------------------------------------\n", + " ID School \n", + "------------------------------------------------------\n", + " Matthew Ortiz 1234 Texas \n", + " Michael Costa 6789 UVA \n", + " Samuel Johnson 1023 UMBC \n", + " Dakota Snyder 5810 UGA \n", + " Scott Mills 9182 Rice \n", + "------------------------------------------------------\n", + "Panel B) Women \n", + "------------------------------------------------------\n", + " ID School \n", + "------------------------------------------------------\n", + " Erin Anderson 9183 Wake Forrest \n", + " Michelle Zimmerman 5734 Emory \n", + " Danielle King 1290 Texas \n", + " Shannon Nelson 4743 UVA \n", + " Stephanie Booth 8912 Columbia \n", + "------------------------------------------------------\n", "\n" ] } @@ -3241,6 +2780,8 @@ " index=[fake.name_female() for _ in range(5)],\n", ")\n", "panelb = tables.GenericTable(panelb_df, formatters={\"ID\": lambda x: f\"{x}\"})\n", + "# panela.table_params[\"double_top_rule\"] = True\n", + "panela.update_parameter(\"double_top_rule\", True)\n", "panel = tables.PanelTable([panela, panelb], [\"Men\", \"Women\"])\n", "print(panel)" ] @@ -3285,166 +2826,102 @@ " \n", " \n", " α\n", - "\n", " 0.092\n", - "\n", " 0.023\n", - "\n", " 1.871\n", - "\n", " \n", " \n", " \n", - "\n", " (0.078)\n", - "\n", " (0.151)\n", - "\n", " (0.038)\n", - "\n", " \n", " \n", " Experience\n", - "\n", " 0.067\n", - "\n", " 0.106\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.014)\n", - "\n", " (0.015)\n", - "\n", " \n", - "\n", " \n", " \n", " Experience²\n", - "\n", " -0.002\n", - "\n", " -0.005\n", - "\n", " -0.005\n", - "\n", " \n", " \n", " \n", - "\n", " (0.001)\n", - "\n", " (0.001)\n", - "\n", " (0.001)\n", - "\n", " \n", " \n", " Union\n", - "\n", " 0.182\n", - "\n", " 0.106\n", - "\n", " 0.080\n", - "\n", " \n", " \n", " \n", - "\n", " (0.017)\n", - "\n", " (0.018)\n", - "\n", " (0.019)\n", - "\n", " \n", " \n", " Married\n", - "\n", " 0.108\n", - "\n", " 0.064\n", - "\n", " 0.047\n", - "\n", " \n", " \n", " \n", - "\n", " (0.016)\n", - "\n", " (0.017)\n", - "\n", " (0.018)\n", - "\n", " \n", " \n", " Black\n", - "\n", " -0.139\n", - "\n", " -0.139\n", - "\n", " \n", - "\n", " \n", " \n", " \n", - "\n", " (0.024)\n", - "\n", " (0.048)\n", - "\n", " \n", - "\n", " \n", " \n", " \n", " \n", " \n", " Observations\n", - "\n", " 4,360\n", - "\n", " 4,360\n", - "\n", " 4,360\n", - "\n", " \n", " \n", " N. Groups\n", - "\n", " 545\n", - "\n", " 545\n", - "\n", " 545\n", - "\n", " \n", " \n", " R2\n", - "\n", " 0.189\n", - "\n", " 0.181\n", - "\n", " 0.022\n", - "\n", " \n", " \n", " F Statistic\n", - "\n", " 72.459\n", - "\n", " 68.409\n", - "\n", " 27.959\n", - "\n", " \n", " \n", " \n", @@ -3453,29 +2930,29 @@ "" ], "text/plain": [ - "==================================================================\n", - "+ Dependent Variable: A Long Title That Would Look Odd +\n", - "+ -------------------------------------------------------------- +\n", - "+ (1) (2) (3) +\n", - "+----------------------------------------------------------------+\n", - "+ α 0.092 0.023 1.871 +\n", - "+ (0.078) (0.151) (0.038) +\n", - "+ Experience 0.067 0.106 +\n", - "+ (0.014) (0.015) +\n", - "+ Experience² -0.002 -0.005 -0.005 +\n", - "+ (0.001) (0.001) (0.001) +\n", - "+ Union 0.182 0.106 0.080 +\n", - "+ (0.017) (0.018) (0.019) +\n", - "+ Married 0.108 0.064 0.047 +\n", - "+ (0.016) (0.017) (0.018) +\n", - "+ Black -0.139 -0.139 +\n", - "+ (0.024) (0.048) +\n", - "------------------------------------------------------------------\n", - "+ Observations 4,360 4,360 4,360 +\n", - "+ N. Groups 545 545 545 +\n", - "+ R² 0.189 0.181 0.022 +\n", - "+ F Statistic 72.459 68.409 27.959 +\n", - "------------------------------------------------------------------" + "================================================================\n", + " Dependent Variable: A Long Title That Would Look Odd \n", + " -------------------------------------------------------------- \n", + " (1) (2) (3) \n", + "----------------------------------------------------------------\n", + " α 0.092 0.023 1.871 \n", + " (0.078) (0.151) (0.038) \n", + " Experience 0.067 0.106 \n", + " (0.014) (0.015) \n", + " Experience² -0.002 -0.005 -0.005 \n", + " (0.001) (0.001) (0.001) \n", + " Union 0.182 0.106 0.080 \n", + " (0.017) (0.018) (0.019) \n", + " Married 0.108 0.064 0.047 \n", + " (0.016) (0.017) (0.018) \n", + " Black -0.139 -0.139 \n", + " (0.024) (0.048) \n", + "----------------------------------------------------------------\n", + " Observations 4,360 4,360 4,360 \n", + " N. Groups 545 545 545 \n", + " R² 0.189 0.181 0.022 \n", + " F Statistic 72.459 68.409 27.959 \n", + "----------------------------------------------------------------" ] }, "execution_count": 32, @@ -3508,29 +2985,29 @@ "name": "stdout", "output_type": "stream", "text": [ - "==================================================================\n", - "+ Dependent Variable: A Long Title That Would Look Odd +\n", - "+ -------------------------------------------------------------- +\n", - "+ (1) (2) (3) +\n", - "+----------------------------------------------------------------+\n", - "+ α 0.092 0.023 1.871 +\n", - "+ (0.078) (0.151) (0.038) +\n", - "+ Experience 0.067 0.106 +\n", - "+ (0.014) (0.015) +\n", - "+ Experience² -0.002 -0.005 -0.005 +\n", - "+ (0.001) (0.001) (0.001) +\n", - "+ Union 0.182 0.106 0.080 +\n", - "+ (0.017) (0.018) (0.019) +\n", - "+ Married 0.108 0.064 0.047 +\n", - "+ (0.016) (0.017) (0.018) +\n", - "+ Black -0.139 -0.139 +\n", - "+ (0.024) (0.048) +\n", - "------------------------------------------------------------------\n", - "+ Observations 4,360 4,360 4,360 +\n", - "+ N. Groups 545 545 545 +\n", - "+ R² 0.189 0.181 0.022 +\n", - "+ F Statistic 72.459 68.409 27.959 +\n", - "------------------------------------------------------------------\n" + "================================================================\n", + " Dependent Variable: A Long Title That Would Look Odd \n", + " -------------------------------------------------------------- \n", + " (1) (2) (3) \n", + "----------------------------------------------------------------\n", + " α 0.092 0.023 1.871 \n", + " (0.078) (0.151) (0.038) \n", + " Experience 0.067 0.106 \n", + " (0.014) (0.015) \n", + " Experience² -0.002 -0.005 -0.005 \n", + " (0.001) (0.001) (0.001) \n", + " Union 0.182 0.106 0.080 \n", + " (0.017) (0.018) (0.019) \n", + " Married 0.108 0.064 0.047 \n", + " (0.016) (0.017) (0.018) \n", + " Black -0.139 -0.139 \n", + " (0.024) (0.048) \n", + "----------------------------------------------------------------\n", + " Observations 4,360 4,360 4,360 \n", + " N. Groups 545 545 545 \n", + " R² 0.189 0.181 0.022 \n", + " F Statistic 72.459 68.409 27.959 \n", + "----------------------------------------------------------------\n" ] } ], @@ -3577,54 +3054,36 @@ " \n", " \n", " X1\n", - "\n", " -0.919***\n", - "\n", " -0.007\n", - "\n", " \n", " \n", " \n", - "\n", " (0.060)\n", - "\n", " (0.042)\n", - "\n", " \n", " \n", " X2\n", - "\n", " \n", - "\n", " -0.015\n", - "\n", " \n", " \n", " \n", - "\n", " \n", - "\n", " (0.011)\n", - "\n", " \n", " \n", " \n", " \n", " \n", " Observations\n", - "\n", " 997\n", - "\n", " 995\n", - "\n", " \n", " \n", " R2\n", - "\n", " 0.609\n", - "\n", " \n", - "\n", " \n", " \n", " \n", @@ -3634,19 +3093,19 @@ "" ], "text/plain": [ - "==================================================\n", - "+ Dependent Variable: Y +\n", - "+ ------------------------------ +\n", - "+ (1) (2) +\n", - "+------------------------------------------------+\n", - "+ X1 -0.919*** -0.007 +\n", - "+ (0.060) (0.042) +\n", - "+ X2 -0.015 +\n", - "+ (0.011) +\n", - "--------------------------------------------------\n", - "+ Observations 997 995 +\n", - "+ R² 0.609 +\n", - "--------------------------------------------------\n", + "================================================\n", + " Dependent Variable: Y \n", + " ------------------------------ \n", + " (1) (2) \n", + "------------------------------------------------\n", + " X1 -0.919*** -0.007 \n", + " (0.060) (0.042) \n", + " X2 -0.015 \n", + " (0.011) \n", + "------------------------------------------------\n", + " Observations 997 995 \n", + " R² 0.609 \n", + "------------------------------------------------\n", "*p<0.1, **p<0.05, ***p<0.01 " ] }, diff --git a/statstables/__init__.py b/statstables/__init__.py index d292b4c..7af6485 100644 --- a/statstables/__init__.py +++ b/statstables/__init__.py @@ -80,5 +80,7 @@ def __getitem__(self, key: Hashable): "linearmodels.panel.results.RandomEffectsResults": modeltables.LinearModelsData, "pyfixest.estimation.feols_.Feols": modeltables.PyFixestModel, "pyfixest.estimation.fepois_.Fepois": modeltables.PyFixestModel, + "pyfixest.estimation.models.feols_.Feols": modeltables.PyFixestModel, + "pyfixest.estimation.models.fepois_.Fepois": modeltables.PyFixestModel, } ) diff --git a/statstables/renderers.py b/statstables/renderers.py index ac81c10..e6ef5ad 100644 --- a/statstables/renderers.py +++ b/statstables/renderers.py @@ -3,6 +3,8 @@ import statstables as st import textwrap from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import Optional from .utils import VALID_LINE_LOCATIONS, replace_latex @@ -262,7 +264,7 @@ def generate_footer(self, only_tabular=False): # longtables already have a bottom rule if not self.table.longtable: footer += " \\bottomrule\n" - if st.STParams["double_bottom_rule"]: + if self.table.table_params["double_bottom_rule"]: footer += " \\bottomrule\n" if self.table.notes: for note, alignment, escape in self.table.notes: @@ -462,7 +464,9 @@ def generate_footer(self, convert_latex=True): if self.table.notes: ncols = self.table.ncolumns + self.table.table_params["include_index"] for note, alignment, _ in self.table.notes: - _notes = textwrap.wrap(note, width=st.STParams["max_html_notes_length"]) + _notes = textwrap.wrap( + note, width=self.table.table_params["max_html_notes_length"] + ) for _note in _notes: _note_str = _note if convert_latex: @@ -530,10 +534,26 @@ def _format_value(self, formatting_dict: dict, **kwargs) -> str: end += "" val = formatting_dict["value"] # create full cell - cell += f"{start}{val}{end}\n" + cell += f"{start}{val}{end}" return cell +@dataclass +class ASCIIWidths: + max_body_cell_size: int + max_index_name_cell_size: int + _len: int + _border_len: int + + def __str__(self) -> str: + return ( + f"max_body_cell_size: {self.max_body_cell_size}\n" + + f"max_index_name_cell_size: {self.max_index_name_cell_size}\n" + + f"_len: {self._len}\n" + + f"_border_len: {self._border_len}" + ) + + class ASCIIRenderer(Renderer): ALIGNMENTS = { "l": "<", @@ -550,7 +570,7 @@ class ASCIIRenderer(Renderer): def __init__(self, table): self.table = table # number of spaces to place on either side of cell values - self.padding = st.STParams["ascii_padding"] + self.padding = self.table.table_params["ascii_padding"] self.ncolumns = self.table.ncolumns + int( self.table.table_params["include_index"] ) @@ -563,9 +583,21 @@ def reset_size_parameters(self): self.max_body_cell_size = 0 self.max_index_name_cell_size = 0 self._len = 0 + self._border_len = 0 + + def set_size_parameters(self, widths: ASCIIWidths): + self.max_body_cell_size = widths.max_body_cell_size + self.max_index_name_cell_size = widths.max_index_name_cell_size + self._len = widths._len + self._border_len = widths._border_len - def render(self, convert_latex=True) -> str: - self._get_table_widths(convert_latex=convert_latex) + def render( + self, convert_latex=True, table_widths: Optional[ASCIIWidths] = None + ) -> str: + if not table_widths: + self._get_table_widths(convert_latex=convert_latex) + else: + self.set_size_parameters(table_widths) out = self.generate_header(convert_latex=convert_latex) out += self.generate_body(convert_latex=convert_latex) out += self.generate_footer(convert_latex=convert_latex) @@ -580,22 +612,24 @@ def generate_header(self, convert_latex=True) -> str: caption = replace_latex(caption) header += f"\n{caption:^{self._len + (2 * self._border_len)}}\n" header += ( - st.STParams["ascii_header_char"] * (self._len + (2 * self._border_len)) + self.table.table_params["ascii_header_char"] + * (self._len + (2 * self._border_len)) + "\n" ) - if st.STParams["ascii_double_top_rule"]: + if self.table.table_params["ascii_double_top_rule"]: header += ( - st.STParams["ascii_header_char"] * (self._len + (2 * self._border_len)) + self.table.table_params["ascii_header_char"] + * (self._len + (2 * self._border_len)) + "\n" ) for row in self.table._multicolumns: - header += st.STParams["ascii_border_char"] + ( + header += self.table.table_params["ascii_border_char"] + ( " " * self.max_index_name_cell_size * self.table.table_params["include_index"] * (1 - row["cover_index"]) ) - underlines = st.STParams[ + underlines = self.table.table_params[ "ascii_border_char" ] + " " * self.max_index_name_cell_size * self.table.table_params[ "include_index" @@ -619,11 +653,13 @@ def generate_header(self, convert_latex=True) -> str: header += f"{_col:{_align}{_size}}" uchar = "-" if c != "" else " " underlines += f"{uchar * (_size - 2):^{_size}}" - header += f"{st.STParams['ascii_border_char']}\n" + header += f"{self.table.table_params['ascii_border_char']}\n" if row["underline"]: - header += underlines + f"{st.STParams['ascii_border_char']}\n" + header += ( + underlines + f"{self.table.table_params['ascii_border_char']}\n" + ) if self.table.table_params["show_columns"]: - header += st.STParams["ascii_border_char"] + header += self.table.table_params["ascii_border_char"] _index_name = self.table.index_name if convert_latex: _index_name = replace_latex(_index_name) @@ -637,16 +673,16 @@ def generate_header(self, convert_latex=True) -> str: if convert_latex: _col = replace_latex(_col) header += f"{_col:^{self.max_body_cell_size}}" - header += f"{st.STParams['ascii_border_char']}\n" + header += f"{self.table.table_params['ascii_border_char']}\n" if self.table.custom_lines["after-columns"]: for line in self.table.custom_lines["after-columns"]: header += self._create_line(line, convert_latex=convert_latex) if self.table.table_params["show_columns"]: header += ( - st.STParams["ascii_border_char"] - + st.STParams["ascii_mid_rule_char"] * (self._len) - + f"{st.STParams['ascii_border_char']}\n" + self.table.table_params["ascii_border_char"] + + self.table.table_params["ascii_mid_rule_char"] * (self._len) + + f"{self.table.table_params['ascii_border_char']}\n" ) return header @@ -655,7 +691,7 @@ def generate_body(self, convert_latex=True) -> str: rows = self.table._create_rows() body = "" for row in rows: - body += st.STParams["ascii_border_char"] + body += self.table.table_params["ascii_border_char"] for i, r in enumerate(row): _size = self.max_body_cell_size _align = self.calign @@ -668,14 +704,14 @@ def generate_body(self, convert_latex=True) -> str: body += " " * self.padding + f"{_val:{_align}{_size}}" else: body += f"{_val:{_align}{_size}}" - body += f"{st.STParams['ascii_border_char']}\n" + body += f"{self.table.table_params['ascii_border_char']}\n" for line in self.table.custom_lines["after-body"]: body += self._create_line(line, convert_latex=convert_latex) if isinstance(self.table, st.tables.ModelTable): body += ( - st.STParams["ascii_mid_rule_char"] + self.table.table_params["ascii_mid_rule_char"] * (self._len + (2 * self._border_len)) + "\n" ) @@ -683,7 +719,7 @@ def generate_body(self, convert_latex=True) -> str: body += self._create_line(line, convert_latex=convert_latex) stats_rows = self.table._create_stats_rows(renderer="ascii") for row in stats_rows: - body += f"{st.STParams['ascii_border_char']}" + body += f"{self.table.table_params['ascii_border_char']}" for i, r in enumerate(row): _size = self.max_body_cell_size _val = self._format_value(r) @@ -694,32 +730,37 @@ def generate_body(self, convert_latex=True) -> str: body += " " * self.padding + f"{_val:{self.ialign}{_size}}" else: body += f"{_val:{self.calign}{_size}}" - body += f"{st.STParams['ascii_border_char']}\n" + body += f"{self.table.table_params['ascii_border_char']}\n" for line in self.table.custom_lines["after-model-stats"]: body += self._create_line(line, convert_latex=convert_latex) return body def generate_footer(self, convert_latex=True) -> str: - footer = st.STParams["ascii_footer_char"] * (self._len + (2 * self._border_len)) - if st.STParams["ascii_double_bottom_rule"]: - footer += st.STParams["ascii_footer_char"] * ( + footer = self.table.table_params["ascii_footer_char"] * ( + self._len + (2 * self._border_len) + ) + if self.table.table_params["ascii_double_bottom_rule"]: + footer += self.table.table_params["ascii_footer_char"] * ( self._len + (2 * self._border_len) ) if self.table.custom_lines["after-footer"]: footer += "\n" for line in self.table.custom_lines["after-footer"]: footer += self._create_line(line, convert_latex=convert_latex) - footer += st.STParams["ascii_footer_char"] * ( + footer += self.table.table_params["ascii_footer_char"] * ( self._len + (2 * self._border_len) ) - if st.STParams["ascii_double_bottom_rule"]: - footer += st.STParams["ascii_footer_char"] * ( + if self.table.table_params["ascii_double_bottom_rule"]: + footer += self.table.table_params["ascii_footer_char"] * ( self._len + (2 * self._border_len) ) if self.table.notes: for note, alignment, _ in self.table.notes: notes = textwrap.wrap( - note, width=min(self._len, st.STParams["max_ascii_notes_length"]) + note, + width=min( + self._len, self.table.table_params["max_ascii_notes_length"] + ), ) _alignment = self.ALIGNMENTS[alignment] for _note in notes: @@ -741,11 +782,11 @@ def _create_line(self, line, convert_latex=True) -> str: _line = "" if line["deliminate"]: _line += ( - st.STParams["ascii_mid_rule_char"] + self.table.table_params["ascii_mid_rule_char"] * (self._len + (2 * self._border_len)) + "\n" ) - _line += st.STParams["ascii_border_char"] + _line += self.table.table_params["ascii_border_char"] label = line["label"] if convert_latex: label = replace_latex(label) @@ -759,7 +800,7 @@ def _create_line(self, line, convert_latex=True) -> str: if convert_latex: _l = replace_latex(l) _line += f"{_l:{self.calign}{self.max_body_cell_size}}" - _line += st.STParams["ascii_border_char"] + "\n" + _line += self.table.table_params["ascii_border_char"] + "\n" return _line def _get_table_widths(self, convert_latex=True) -> None: @@ -855,7 +896,7 @@ def _get_table_widths(self, convert_latex=True) -> None: self._len = self.max_body_cell_size * self.table.ncolumns self._len += self.max_index_name_cell_size - self._border_len = len(st.STParams["ascii_border_char"]) + self._border_len = len(self.table.table_params["ascii_border_char"]) def _format_value(self, formatting_dict: dict, **kwargs) -> str: return formatting_dict["value"] diff --git a/statstables/tables.py b/statstables/tables.py index 0a6e2f1..fd22bfe 100644 --- a/statstables/tables.py +++ b/statstables/tables.py @@ -1,4 +1,5 @@ import copy +import math import numbers from abc import ABC, abstractmethod from collections import ChainMap, defaultdict @@ -15,7 +16,13 @@ from .cellformatting import DEFAULT_FORMATS, validate_format_dict from .parameters import MeanDiffsTableParams, ModelTableParams, TableParams -from .renderers import ASCIIRenderer, HTMLRenderer, LatexRenderer, TypstRenderer +from .renderers import ( + ASCIIRenderer, + HTMLRenderer, + LatexRenderer, + TypstRenderer, + ASCIIWidths, +) from .utils import VALID_LINE_LOCATIONS, latex_preamble, pstars, validate_line_location @@ -1812,8 +1819,6 @@ def __init__( ): for table in panels: assert isinstance(table, Table) - # must use tabularx to get alignment right - table.table_params["use_tabularx"] = True self.npanels = len(panels) nlabels = len(panel_labels) if len(panels) > len(panel_labels): @@ -1850,17 +1855,29 @@ def render_latex(self, outfile: str | Path | None = None, **kwargs) -> str | Non self.label_char = "i" case _: self.label_char = "" + # tex_str = "\\toprule\n" + # if self.panels[0].table_params["double_top_rule"]: + # tex_str += "\\toprule\n" tex_str = "" for i, (table, label) in enumerate(zip(self.panels, self.panel_labels)): - # if it is not the first table, turn off double top rule - if i != 0: - table.table_params["double_top_rule"] = False + # turn off double top rule to make it look more neat + double_top_rule = table.table_params["double_top_rule"] + table.table_params["double_top_rule"] = False + tabularx_rule = table.table_params["use_tabularx"] + # must use tabularx to get alignment right + table.table_params["use_tabularx"] = True # add multicolumn to the table label_str = f"Panel {self.label_char}: {label}" table.panel_label = label_str table.panel_label_alignment = self.ALIGNMENTS[self.panel_label_alignment] _tex_str = table.render_latex(outfile=None, only_tabular=True) assert isinstance(_tex_str, str) + # put top rule over first panel label + if i == 0: + new_str = "X}\n \\toprule\n" + if double_top_rule: + new_str += " \\toprule\n" + _tex_str = _tex_str.replace("X}\n", new_str) if i < self.npanels - 1: # add space between previous panel and label for next one # except for the very last panel @@ -1870,6 +1887,9 @@ def render_latex(self, outfile: str | Path | None = None, **kwargs) -> str | Non ) tex_str += "\n" + _tex_str self._increment_label_char() + # reset changed settings + table.table_params["double_top_rule"] = double_top_rule + table.table_params["use_tabularx"] = tabularx_rule if not outfile: return tex_str @@ -1893,28 +1913,114 @@ def render_ascii(self, convert_latex: bool = True) -> str: self.label_char = "" # get all the table widths to know how large to make panels max_width = 0 + max_index = 0 + border_lens = [] for table in self.panels: renderer = ASCIIRenderer(table) renderer._get_table_widths() table_size = renderer._len + (2 * renderer._border_len) + border_lens.append(2 * renderer._border_len) max_width = max(max_width, table_size) + max_index = max(max_index, renderer.max_index_name_cell_size) # loop through the tables and actually make them. add all together for panels - out_str = "" + top_rule_char = self.panels[0].table_params["ascii_header_char"] + out_str = top_rule_char * max_width + "\n" for i, (table, label) in enumerate(zip(self.panels, self.panel_labels)): # if it is not the first table, turn off double top rule - if i != 0: - table.table_params["double_top_rule"] = False + # TODO: Reconsider. may be reasonable to leave to user setting + original_top_rule = table.table_params["ascii_double_top_rule"] + orginal_header_char = table.table_params["ascii_header_char"] + table.table_params["ascii_double_top_rule"] = False + table.table_params["ascii_header_char"] = "-" # add multicolumn to the table _label = f"Panel {self.label_char}) {label}" label_align = self.ASCII_ALIGNMENTS[self.panel_label_alignment] label_str = f"{_label:{label_align}{max_width}}\n" - table_str = table.render_ascii(convert_latex=convert_latex) + # set table widths + # calculate the width not used for the index or border + remainder = max_width - max_index - border_lens[i] + colsize = remainder / table.ncolumns + _len = max_width - border_lens[i] + widths = ASCIIWidths( + max_body_cell_size=math.ceil(colsize), + max_index_name_cell_size=math.ceil(max_index), + _len=math.ceil(_len), + _border_len=border_lens[i], + ) + renderer = ASCIIRenderer(table) + table_str = renderer.render( + convert_latex=convert_latex, table_widths=widths + ) out_str += label_str + table_str + "\n" self._increment_label_char() + # reset changed parameters + table.table_params["ascii_double_top_rule"] = original_top_rule + table.table_params["ascii_header_char"] = orginal_header_char return out_str + @overload + def render_html( + self, + outfile: None = None, + table_class: str | None = None, + convert_latex: bool = True, + *args, + **kwargs, + ) -> str: ... + @overload + def render_html( + self, + outfile: str | Path, + table_class: str | None = None, + convert_latex: bool = True, + *args, + **kwargs, + ) -> None: ... + + def render_html( + self, + outfile: str | Path | None = None, + table_class: str | None = None, + convert_latex: bool = True, + *args, + **kwargs, + ) -> str | None: + match self.enumerate_type: + case "alpha_upper": + self.label_char = "A" + case "alpha_lower": + self.label_char = "a" + case "int": + self.label_char = "1" + case "roman": + self.label_char = "i" + case _: + self.label_char = "" + + table_str = "\n" + if table_class: + table_str = f'
\n' + for i, (table, label) in enumerate(zip(self.panels, self.panel_labels)): + _label = f"Panel {self.label_char}) {label}" + _table = table.render_html(convert_latex=convert_latex) + # strip out original table bounds + _table = _table.replace("
\n", "").replace("
", "") + table_str += ( + f'\n {_label}\n' + ) + table_str += _table + # deliminate panels + if i != len(self.panels) - 1: + table_str += " \n" + self._increment_label_char() + table_str += "" + if not outfile: + return table_str + Path(outfile).write_text(table_str) + return None + @overload def render_typst( self,