[
  {
    "objectID": "table-layout.html",
    "href": "table-layout.html",
    "title": "Regression Tables via pf.etable()",
    "section": "",
    "text": "Pyfixest comes with functions to generate publication-ready tables. Regression tables are generated with pf.etable(), which can output different formats, for instance using the Great Tables package or generating formatted LaTex Tables using booktabs. There are also further functions pf.dtable() to display descriptive statistics and pf.make_table() generating formatted tables from pandas dataframes in the same layout.\nTo begin, we load some libraries and fit a set of regression models.\n\nimport numpy as np\nimport pandas as pd\nimport pylatex as pl  # for the latex table; note: not a dependency of pyfixest - needs manual installation\nfrom great_tables import loc, style\nfrom IPython.display import FileLink, display\n\nimport pyfixest as pf\n\n%load_ext autoreload\n%autoreload 2\n\ndata = pf.get_data()\n\nfit1 = pf.feols(\"Y ~ X1 + X2 | f1\", data=data)\nfit2 = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data=data)\nfit3 = pf.feols(\"Y ~ X1 *X2 | f1 + f2\", data=data)\nfit4 = pf.feols(\"Y2 ~ X1 + X2 | f1\", data=data)\nfit5 = pf.feols(\"Y2 ~ X1 + X2 | f1 + f2\", data=data)\nfit6 = pf.feols(\"Y2 ~ X1 *X2 | f1 + f2\", data=data)"
  },
  {
    "objectID": "table-layout.html#table-layout-with-pyfixest",
    "href": "table-layout.html#table-layout-with-pyfixest",
    "title": "Regression Tables via pf.etable()",
    "section": "",
    "text": "Pyfixest comes with functions to generate publication-ready tables. Regression tables are generated with pf.etable(), which can output different formats, for instance using the Great Tables package or generating formatted LaTex Tables using booktabs. There are also further functions pf.dtable() to display descriptive statistics and pf.make_table() generating formatted tables from pandas dataframes in the same layout.\nTo begin, we load some libraries and fit a set of regression models.\n\nimport numpy as np\nimport pandas as pd\nimport pylatex as pl  # for the latex table; note: not a dependency of pyfixest - needs manual installation\nfrom great_tables import loc, style\nfrom IPython.display import FileLink, display\n\nimport pyfixest as pf\n\n%load_ext autoreload\n%autoreload 2\n\ndata = pf.get_data()\n\nfit1 = pf.feols(\"Y ~ X1 + X2 | f1\", data=data)\nfit2 = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data=data)\nfit3 = pf.feols(\"Y ~ X1 *X2 | f1 + f2\", data=data)\nfit4 = pf.feols(\"Y2 ~ X1 + X2 | f1\", data=data)\nfit5 = pf.feols(\"Y2 ~ X1 + X2 | f1 + f2\", data=data)\nfit6 = pf.feols(\"Y2 ~ X1 *X2 | f1 + f2\", data=data)"
  },
  {
    "objectID": "table-layout.html#basic-usage",
    "href": "table-layout.html#basic-usage",
    "title": "Regression Tables via pf.etable()",
    "section": "Basic Usage",
    "text": "Basic Usage\nWe can compare all regression models via the pyfixest-internal pf.etable() function:\n\npf.etable([fit1, fit2, fit3, fit4, fit5, fit6])\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X1\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    X2\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    X1:X2\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    f2\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    f1\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)\n  \n\n\n\n\n\n\n        \n\n\nYou can also estimate and display multiple regressions with one line of code using the (py)fixest stepwise notation:\n\npf.etable(pf.feols(\"Y+Y2~csw(X1,X2,X1:X2)\", data=data))\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X1\n    -1.000***  (0.085)\n    -0.993***  (0.082)\n    -0.992***  (0.082)\n    -1.322***  (0.215)\n    -1.316***  (0.214)\n    -1.316***  (0.215)\n  \n  \n    X2\n    \n    -0.176***  (0.022)\n    -0.197***  (0.036)\n    \n    -0.133*  (0.057)\n    -0.132  (0.095)\n  \n  \n    X1:X2\n    \n    \n    0.020  (0.027)\n    \n    \n    -0.001  (0.071)\n  \n  \n    Intercept\n    0.919***  (0.112)\n    0.889***  (0.108)\n    0.888***  (0.108)\n    1.064***  (0.283)\n    1.042***  (0.283)\n    1.042***  (0.283)\n  \n  \n    stats\n  \n  \n    Observations\n    998\n    998\n    998\n    999\n    999\n    999\n  \n  \n    S.E. type\n    iid\n    iid\n    iid\n    iid\n    iid\n    iid\n  \n  \n    R2\n    0.123\n    0.177\n    0.177\n    0.037\n    0.042\n    0.042\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "table-layout.html#keep-and-drop-variables",
    "href": "table-layout.html#keep-and-drop-variables",
    "title": "Regression Tables via pf.etable()",
    "section": "Keep and drop variables",
    "text": "Keep and drop variables\netable allows us to do a few things out of the box. For example, we can only keep the variables that we’d like, which keeps all variables that fit the provided regex match.\n\npf.etable([fit1, fit2, fit3, fit4, fit5, fit6], keep=\"X1\")\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X1\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    X1:X2\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    f2\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    f1\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)\n  \n\n\n\n\n\n\n        \n\n\nWe can use the exact_match argument to select a specific set of variables:\n\npf.etable([fit1, fit2, fit3, fit4, fit5, fit6], keep=[\"X1\", \"X2\"], exact_match=True)\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X1\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    X2\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    fe\n  \n  \n    f2\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    f1\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)\n  \n\n\n\n\n\n\n        \n\n\nWe can also easily drop variables via the drop argument:\n\npf.etable([fit1, fit2, fit3, fit4, fit5, fit6], drop=[\"X1\"])\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X2\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    fe\n  \n  \n    f2\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    f1\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "table-layout.html#hide-fixed-effects-or-se-type-rows",
    "href": "table-layout.html#hide-fixed-effects-or-se-type-rows",
    "title": "Regression Tables via pf.etable()",
    "section": "Hide fixed effects or SE-type rows",
    "text": "Hide fixed effects or SE-type rows\nWe can hide the rows showing the relevant fixed effects and those showing the S.E. type by setting show_fe=False and show_setype=False (for instance when the set of fixed effects or the estimation method for the std. errors is the same for all models and you want to describe this in the text or table notes rather than displaying it in the table).\n\npf.etable([fit1, fit2, fit3, fit4, fit5, fit6], show_fe=False, show_se_type=False)\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X1\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    X2\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    X1:X2\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "table-layout.html#display-p-values-or-confidence-intervals",
    "href": "table-layout.html#display-p-values-or-confidence-intervals",
    "title": "Regression Tables via pf.etable()",
    "section": "Display p-values or confidence intervals",
    "text": "Display p-values or confidence intervals\nBy default, pf.etable() reports standard errors. But we can also ask to output p-values or confidence intervals via the coef_fmt function argument.\n\npf.etable([fit1, fit2, fit3, fit4, fit5, fit6], coef_fmt=\"b \\n (se) \\n [p]\")\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X1\n    -0.950***  (0.067)  [0.000]\n    -0.924***  (0.061)  [0.000]\n    -0.924***  (0.061)  [0.000]\n    -1.267***  (0.174)  [0.000]\n    -1.232***  (0.192)  [0.000]\n    -1.231***  (0.192)  [0.000]\n  \n  \n    X2\n    -0.174***  (0.018)  [0.000]\n    -0.174***  (0.015)  [0.000]\n    -0.185***  (0.025)  [0.000]\n    -0.131**  (0.042)  [0.005]\n    -0.118**  (0.042)  [0.008]\n    -0.074  (0.104)  [0.482]\n  \n  \n    X1:X2\n    \n    \n    0.011  (0.018)  [0.565]\n    \n    \n    -0.041  (0.081)  [0.618]\n  \n  \n    fe\n  \n  \n    f2\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    f1\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error) \n [p-value]"
  },
  {
    "objectID": "table-layout.html#significance-levels-and-rounding",
    "href": "table-layout.html#significance-levels-and-rounding",
    "title": "Regression Tables via pf.etable()",
    "section": "Significance levels and rounding",
    "text": "Significance levels and rounding\nAdditionally, we can also overwrite the defaults for the reported significance levels and control the rounding of results via the signif_code and digits function arguments:\n\npf.etable([fit1, fit2, fit3, fit4, fit5, fit6], signif_code=[0.01, 0.05, 0.1], digits=5)\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X1\n    -0.94953***  (0.06652)\n    -0.92405***  (0.06093)\n    -0.92417***  (0.06094)\n    -1.26655***  (0.17359)\n    -1.23153***  (0.19228)\n    -1.23100***  (0.19167)\n  \n  \n    X2\n    -0.17423***  (0.01840)\n    -0.17411***  (0.01461)\n    -0.18550***  (0.02516)\n    -0.13056***  (0.04239)\n    -0.11767***  (0.04152)\n    -0.07369  (0.10356)\n  \n  \n    X1:X2\n    \n    \n    0.01057  (0.01818)\n    \n    \n    -0.04082  (0.08093)\n  \n  \n    fe\n  \n  \n    f2\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    f1\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.48899\n    0.65904\n    0.65916\n    0.12017\n    0.17151\n    0.17180\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.1, ** p &lt; 0.05, *** p &lt; 0.01. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "table-layout.html#other-output-formats",
    "href": "table-layout.html#other-output-formats",
    "title": "Regression Tables via pf.etable()",
    "section": "Other output formats",
    "text": "Other output formats\nBy default, pf.etable() returns a GT object (see the Great Tables package), but you can also opt to dataframe, markdown, or latex output via the type argument.\n\n# Pandas styler output:\npf.etable(\n    [fit1, fit2, fit3, fit4, fit5, fit6],\n    signif_code=[0.01, 0.05, 0.1],\n    digits=5,\n    coef_fmt=\"b (se)\",\n    type=\"df\",\n)\n\n\n\n\n  \n    \n      \n      est1\n      est2\n      est3\n      est4\n      est5\n      est6\n    \n  \n  \n    \n      depvar\n      Y\n      Y\n      Y\n      Y2\n      Y2\n      Y2\n    \n    \n      X1\n      -0.94953*** (0.06652)\n      -0.92405*** (0.06093)\n      -0.92417*** (0.06094)\n      -1.26655*** (0.17359)\n      -1.23153*** (0.19228)\n      -1.23100*** (0.19167)\n    \n    \n      X2\n      -0.17423*** (0.01840)\n      -0.17411*** (0.01461)\n      -0.18550*** (0.02516)\n      -0.13056*** (0.04239)\n      -0.11767*** (0.04152)\n      -0.07369 (0.10356)\n    \n    \n      X1:X2\n      \n      \n      0.01057 (0.01818)\n      \n      \n      -0.04082 (0.08093)\n    \n    \n      f2\n      -\n      x\n      x\n      -\n      x\n      x\n    \n    \n      f1\n      x\n      x\n      x\n      x\n      x\n      x\n    \n    \n      Observations\n      997\n      997\n      997\n      998\n      998\n      998\n    \n    \n      S.E. type\n      by: f1\n      by: f1\n      by: f1\n      by: f1\n      by: f1\n      by: f1\n    \n    \n      R2\n      0.48899\n      0.65904\n      0.65916\n      0.12017\n      0.17151\n      0.17180\n    \n  \n\n\n\n\n\n# Markdown output:\npf.etable(\n    [fit1, fit2, fit3, fit4, fit5, fit6],\n    signif_code=[0.01, 0.05, 0.1],\n    digits=5,\n    type=\"md\",\n)\n\nindex                 est1          est2          est3          est4          est5          est6\n------------  ------------  ------------  ------------  ------------  ------------  ------------\ndepvar                   Y             Y             Y            Y2            Y2            Y2\n------------------------------------------------------------------------------------------------\nX1            -0.94953***   -0.92405***   -0.92417***   -1.26655***   -1.23153***   -1.23100***\n                 (0.06652)     (0.06093)     (0.06094)     (0.17359)     (0.19228)     (0.19167)\nX2            -0.17423***   -0.17411***   -0.18550***   -0.13056***   -0.11767***      -0.07369\n                 (0.01840)     (0.01461)     (0.02516)     (0.04239)     (0.04152)     (0.10356)\nX1:X2                                         0.01057                                  -0.04082\n                                             (0.01818)                                 (0.08093)\n------------------------------------------------------------------------------------------------\nf2                       -             x             x             -             x             x\nf1                       x             x             x             x             x             x\n------------------------------------------------------------------------------------------------\nObservations           997           997           997           998           998           998\nS.E. type           by: f1        by: f1        by: f1        by: f1        by: f1        by: f1\nR2                 0.48899       0.65904       0.65916       0.12017       0.17151       0.17180\n------------------------------------------------------------------------------------------------\n\n\n\nTo obtain latex output use format = \"tex\". If you want to save the table as a tex file, you can use the filename= argument to specify the respective path where it should be saved. If you want the latex code to be displayed in the notebook, you can use the print_tex=True argument. Etable will use latex packages booktabs, threeparttable and makecell for the table layout, so don’t forget to include these packages in your latex document.\n\n# LaTex output (include latex packages booktabs, threeparttable, and makecell in your document):\ntab = pf.etable(\n    [fit1, fit2, fit3, fit4, fit5, fit6],\n    signif_code=[0.01, 0.05, 0.1],\n    digits=2,\n    type=\"tex\",\n    print_tex=True,\n)\n\nThe following code generates a pdf including the regression table which you can display clicking on the link below the cell:\n\n## Use pylatex to create a tex file with the table\n\n\ndef make_pdf(tab, file):\n    \"Create a PDF document with tex table.\"\n    doc = pl.Document()\n    doc.packages.append(pl.Package(\"booktabs\"))\n    doc.packages.append(pl.Package(\"threeparttable\"))\n    doc.packages.append(pl.Package(\"makecell\"))\n\n    with (\n        doc.create(pl.Section(\"A PyFixest LateX Table\")),\n        doc.create(pl.Table(position=\"htbp\")) as table,\n    ):\n        table.append(pl.NoEscape(tab))\n\n    doc.generate_pdf(file, clean_tex=False)\n\n\n# Compile latex to pdf & display a button with the hyperlink to the pdf\n# requires tex installation\nrun = False\nif run:\n    make_pdf(tab, \"latexdocs/SampleTableDoc\")\ndisplay(FileLink(\"latexdocs/SampleTableDoc.pdf\"))\n\nlatexdocs/SampleTableDoc.pdf"
  },
  {
    "objectID": "table-layout.html#rename-variables",
    "href": "table-layout.html#rename-variables",
    "title": "Regression Tables via pf.etable()",
    "section": "Rename variables",
    "text": "Rename variables\nYou can also rename variables if you want to have a more readable output. Just pass a dictionary to the labels argument. Note that interaction terms will also be relabeled using the specified labels for the interacted variables (if you want to manually relabel an interaction term differently, add it to the dictionary).\n\nlabels = {\n    \"Y\": \"Wage\",\n    \"Y2\": \"Wealth\",\n    \"X1\": \"Age\",\n    \"X2\": \"Years of Schooling\",\n    \"f1\": \"Industry\",\n    \"f2\": \"Year\",\n}\n\npf.etable([fit1, fit2, fit3, fit4, fit5, fit6], labels=labels)\n\n\n\n\n\n\n\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    Industry\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)\n  \n\n\n\n\n\n\n        \n\n\nIf you want to label the rows indicating the inclusion of fixed effects not with the variable label but with a custom label, you can pass on a separate dictionary to the felabels argument.\n\npf.etable(\n    [fit1, fit2, fit3, fit4, fit5, fit6],\n    labels=labels,\n    felabels={\"f1\": \"Industry Fixed Effects\", \"f2\": \"Year Fixed Effects\"},\n)\n\n\n\n\n\n\n\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year Fixed Effects\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    Industry Fixed Effects\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "table-layout.html#custom-model-headlines",
    "href": "table-layout.html#custom-model-headlines",
    "title": "Regression Tables via pf.etable()",
    "section": "Custom model headlines",
    "text": "Custom model headlines\nYou can also add custom headers for each model by passing a list of strings to the model_headers argument.\n\npf.etable(\n    [fit1, fit2, fit3, fit4, fit5, fit6],\n    labels=labels,\n    model_heads=[\"US\", \"China\", \"EU\", \"US\", \"China\", \"EU\"],\n)\n\n\n\n\n\n\n\n  \n     \n  \n  \n    Wage\n  \n  \n    Wealth\n  \n\n\n  \n  \n    US\n  \n  \n    China\n  \n  \n    EU\n  \n  \n    US\n  \n  \n    China\n  \n  \n    EU\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    Industry\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)\n  \n\n\n\n\n\n\n        \n\n\nOr change the ordering of headlines having headlines first and then dependent variables using the head_order argument. “hd” stands for headlines then dependent variables, “dh” for dependent variables then headlines. Assigning “d” or “h” can be used to only show dependent variables or only headlines. When head_order=“” only model numbers are shown.\n\npf.etable(\n    [fit1, fit4, fit2, fit5, fit3, fit6],\n    labels=labels,\n    model_heads=[\"US\", \"US\", \"China\", \"China\", \"EU\", \"EU\"],\n    head_order=\"hd\",\n)\n\n\n\n\n\n\n\n  \n     \n  \n  \n    US\n  \n  \n    China\n  \n  \n    EU\n  \n\n\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -1.267***  (0.174)\n    -0.924***  (0.061)\n    -1.232***  (0.192)\n    -0.924***  (0.061)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.131**  (0.042)\n    -0.174***  (0.015)\n    -0.118**  (0.042)\n    -0.185***  (0.025)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    \n    \n    0.011  (0.018)\n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year\n    -\n    -\n    x\n    x\n    x\n    x\n  \n  \n    Industry\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    998\n    997\n    998\n    997\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.120\n    0.659\n    0.172\n    0.659\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)\n  \n\n\n\n\n\n\n        \n\n\nRemove the dependent variables from the headers:\n\npf.etable(\n    [fit1, fit4, fit2, fit5, fit3, fit6],\n    labels=labels,\n    model_heads=[\"US\", \"US\", \"China\", \"China\", \"EU\", \"EU\"],\n    head_order=\"\",\n)\n\n\n\n\n\n\n\n  \n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -1.267***  (0.174)\n    -0.924***  (0.061)\n    -1.232***  (0.192)\n    -0.924***  (0.061)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.131**  (0.042)\n    -0.174***  (0.015)\n    -0.118**  (0.042)\n    -0.185***  (0.025)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    \n    \n    0.011  (0.018)\n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year\n    -\n    -\n    x\n    x\n    x\n    x\n  \n  \n    Industry\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    998\n    997\n    998\n    997\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.120\n    0.659\n    0.172\n    0.659\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "table-layout.html#further-custom-model-information",
    "href": "table-layout.html#further-custom-model-information",
    "title": "Regression Tables via pf.etable()",
    "section": "Further custom model information",
    "text": "Further custom model information\nYou can add further custom model statistics/information to the bottom of the table by using the custom_stats argument to which you pass a dictionary with the name of the row and lists of values. The length of the lists must be equal to the number of models.\n\npf.etable(\n    [fit1, fit2, fit3, fit4, fit5, fit6],\n    labels=labels,\n    custom_model_stats={\n        \"Number of Clusters\": [42, 42, 42, 37, 37, 37],\n        \"Additional Info\": [\"A\", \"A\", \"B\", \"B\", \"C\", \"C\"],\n    },\n)\n\n\n\n\n\n\n\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    Industry\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Number of Clusters\n    42\n    42\n    42\n    37\n    37\n    37\n  \n  \n    Additional Info\n    A\n    A\n    B\n    B\n    C\n    C\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "table-layout.html#custom-table-notes",
    "href": "table-layout.html#custom-table-notes",
    "title": "Regression Tables via pf.etable()",
    "section": "Custom table notes",
    "text": "Custom table notes\nYou can replace the default table notes with your own notes using the notes argument.\n\nmynotes = \"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\"\npf.etable(\n    [fit1, fit4, fit2, fit5, fit3, fit6],\n    labels=labels,\n    model_heads=[\"US\", \"US\", \"China\", \"China\", \"EU\", \"EU\"],\n    head_order=\"hd\",\n    notes=mynotes,\n)\n\n\n\n\n\n\n\n  \n     \n  \n  \n    US\n  \n  \n    China\n  \n  \n    EU\n  \n\n\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -1.267***  (0.174)\n    -0.924***  (0.061)\n    -1.232***  (0.192)\n    -0.924***  (0.061)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.131**  (0.042)\n    -0.174***  (0.015)\n    -0.118**  (0.042)\n    -0.185***  (0.025)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    \n    \n    0.011  (0.018)\n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year\n    -\n    -\n    x\n    x\n    x\n    x\n  \n  \n    Industry\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    998\n    997\n    998\n    997\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.120\n    0.659\n    0.172\n    0.659\n    0.172\n  \n\n  \n  \n  \n    Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
  },
  {
    "objectID": "table-layout.html#publication-ready-latex-tables",
    "href": "table-layout.html#publication-ready-latex-tables",
    "title": "Regression Tables via pf.etable()",
    "section": "Publication-ready LaTex tables",
    "text": "Publication-ready LaTex tables\nWith few lines of code you thus obtain a publication-ready latex table:\n\ntab = pf.etable(\n    [fit1, fit4, fit2, fit5, fit3, fit6],\n    labels=labels,\n    model_heads=[\"US\", \"US\", \"China\", \"China\", \"EU\", \"EU\"],\n    head_order=\"hd\",\n    type=\"tex\",\n    notes=mynotes,\n    show_fe=True,\n    show_se_type=False,\n    custom_model_stats={\n        \"Number of Clusters\": [42, 42, 42, 37, 37, 37],\n    },\n)\n\n# Compile latex to pdf & display a button with the hyperlink to the pdf\nrun = False\nif run:\n    make_pdf(tab, \"latexdocs/SampleTableDoc2\")\ndisplay(FileLink(\"latexdocs/SampleTableDoc2.pdf\"))\n\nlatexdocs/SampleTableDoc2.pdf"
  },
  {
    "objectID": "table-layout.html#basic-usage-of-dtable",
    "href": "table-layout.html#basic-usage-of-dtable",
    "title": "Regression Tables via pf.etable()",
    "section": "Basic Usage of dtable",
    "text": "Basic Usage of dtable\nSpecify the variables you want to display the descriptive statistics for. You can also use a dictionary to rename the variables and add a caption.\n\npf.dtable(\n    data,\n    vars=[\"Y\", \"Y2\", \"X1\", \"X2\"],\n    labels=labels,\n    caption=\"Descriptive statistics\",\n    digits=2,\n)\n\n\n\n\n\n\n  \n    Descriptive statistics\n  \n\n  \n  N\n  Mean\n  Std. Dev.\n\n\n\n  \n    Wage\n    999\n    -0.13\n    2.30\n  \n  \n    Wealth\n    1000\n    -0.31\n    5.58\n  \n  \n    Age\n    999\n    1.04\n    0.81\n  \n  \n    Years of Schooling\n    1000\n    -0.13\n    3.05\n  \n\n  \n  \n  \n    \n  \n\n\n\n\n\n\n        \n\n\nChoose the set of statistics to be displayed with stats. You can use any pandas aggregation functions.\n\npf.dtable(\n    data,\n    vars=[\"Y\", \"Y2\", \"X1\", \"X2\"],\n    stats=[\"count\", \"mean\", \"std\", \"min\", \"max\"],\n    labels=labels,\n    caption=\"Descriptive statistics\",\n)\n\n\n\n\n\n\n  \n    Descriptive statistics\n  \n\n  \n  N\n  Mean\n  Std. Dev.\n  Min\n  Max\n\n\n\n  \n    Wage\n    999\n    -0.13\n    2.30\n    -6.54\n    6.91\n  \n  \n    Wealth\n    1000\n    -0.31\n    5.58\n    -16.97\n    17.16\n  \n  \n    Age\n    999\n    1.04\n    0.81\n    0.00\n    2.00\n  \n  \n    Years of Schooling\n    1000\n    -0.13\n    3.05\n    -9.67\n    10.99"
  },
  {
    "objectID": "table-layout.html#summarize-by-characteristics-in-columns-and-rows",
    "href": "table-layout.html#summarize-by-characteristics-in-columns-and-rows",
    "title": "Regression Tables via pf.etable()",
    "section": "Summarize by characteristics in columns and rows",
    "text": "Summarize by characteristics in columns and rows\nYou can summarize by characteristics using the bycol argument when groups are to be displayed in columns. When the number of observations is the same for all variables in a group, you can also opt to display the number of observations only once for each group byin a separate line at the bottom of the table with counts_row_below==True.\n\n# Generate some categorial data\ndata[\"country\"] = np.random.choice([\"US\", \"EU\"], data.shape[0])\ndata[\"occupation\"] = np.random.choice([\"Blue collar\", \"White collar\"], data.shape[0])\n\n# Drop nan values to have balanced data\ndata.dropna(inplace=True)\n\npf.dtable(\n    data,\n    vars=[\"Y\", \"Y2\", \"X1\", \"X2\"],\n    labels=labels,\n    bycol=[\"country\", \"occupation\"],\n    stats=[\"count\", \"mean\", \"std\"],\n    caption=\"Descriptive statistics\",\n    stats_labels={\"count\": \"Number of observations\"},\n    counts_row_below=True,\n)\n\n\n\n\n\n\n  \n    Descriptive statistics\n  \n\n  \n     \n  \n  \n    EU\n  \n  \n    US\n  \n\n\n  \n  \n    Blue collar\n  \n  \n    White collar\n  \n  \n    Blue collar\n  \n  \n    White collar\n  \n\n\n  Mean\n  Std. Dev.\n  Mean\n  Std. Dev.\n  Mean\n  Std. Dev.\n  Mean\n  Std. Dev.\n\n\n\n  \n    stats\n  \n  \n    Wage\n    -0.24\n    2.14\n    -0.33\n    2.36\n    0.02\n    2.38\n    0.07\n    2.31\n  \n  \n    Wealth\n    0.05\n    5.38\n    -0.45\n    5.75\n    -0.27\n    5.82\n    -0.60\n    5.35\n  \n  \n    Age\n    1.00\n    0.82\n    1.06\n    0.79\n    1.05\n    0.83\n    1.05\n    0.79\n  \n  \n    Years of Schooling\n    -0.00\n    3.15\n    -0.05\n    2.98\n    -0.21\n    2.94\n    -0.26\n    3.15\n  \n  \n    nobs\n  \n  \n    Number of observations\n    240\n    \n    277\n    \n    255\n    \n    225\n    \n  \n\n  \n  \n  \n    \n  \n\n\n\n\n\n\n        \n\n\nYou can also use custom aggregation functions to compute further statistics or affect how statistics are presented. Pyfixest provides two such functions mean_std and mean_newline_std which compute the mean and standard deviation and display both the same cell (either with line break between them or not). This allows to have more compact tables when you want to show statistics for many characteristcs in the columns.\nYou can also hide the display of the statistics labels in the header with hide_stats_labels=True. In that case a table note will be added naming the statistics displayed using its label (if you have not provided a custom note).\n\npf.dtable(\n    data,\n    vars=[\"Y\", \"Y2\", \"X1\", \"X2\"],\n    labels=labels,\n    bycol=[\"country\", \"occupation\"],\n    stats=[\"mean_newline_std\", \"count\"],\n    caption=\"Descriptive statistics\",\n    stats_labels={\"count\": \"Number of observations\"},\n    counts_row_below=True,\n    hide_stats=True,\n)\n\n\n\n\n\n\n  \n    Descriptive statistics\n  \n\n  \n  \n    EU\n  \n  \n    US\n  \n\n\n  Blue collar\n  White collar\n  Blue collar\n  White collar\n\n\n\n  \n    stats\n  \n  \n    Wage\n    -0.24(2.14)\n    -0.33(2.36)\n    0.02(2.38)\n    0.07(2.31)\n  \n  \n    Wealth\n    0.05(5.38)\n    -0.45(5.75)\n    -0.27(5.82)\n    -0.60(5.35)\n  \n  \n    Age\n    1.00(0.82)\n    1.06(0.79)\n    1.05(0.83)\n    1.05(0.79)\n  \n  \n    Years of Schooling\n    -0.00(3.15)\n    -0.05(2.98)\n    -0.21(2.94)\n    -0.26(3.15)\n  \n  \n    nobs\n  \n  \n    Number of observations\n    240\n    277\n    255\n    225\n  \n\n  \n  \n  \n    Note: Displayed statistics are Mean (Std. Dev.).\n  \n\n\n\n\n\n\n        \n\n\nYou can also split by characteristics in both columns and rows. Note that you can only use one grouping variable in rows, but several in columns (as shown above).\n\npf.dtable(\n    data,\n    vars=[\"Y\", \"Y2\", \"X1\", \"X2\"],\n    labels=labels,\n    bycol=[\"country\"],\n    byrow=\"occupation\",\n    stats=[\"count\", \"mean\", \"std\"],\n    caption=\"Descriptive statistics\",\n)\n\n\n\n\n\n\n  \n    Descriptive statistics\n  \n\n  \n  \n    EU\n  \n  \n    US\n  \n\n\n  N\n  Mean\n  Std. Dev.\n  N\n  Mean\n  Std. Dev.\n\n\n\n  \n    Blue collar\n  \n  \n    Wage\n    240\n    -0.24\n    2.14\n    255\n    0.02\n    2.38\n  \n  \n    Wealth\n    240\n    0.05\n    5.38\n    255\n    -0.27\n    5.82\n  \n  \n    Age\n    240\n    1.00\n    0.82\n    255\n    1.05\n    0.83\n  \n  \n    Years of Schooling\n    240\n    -0.00\n    3.15\n    255\n    -0.21\n    2.94\n  \n  \n    White collar\n  \n  \n    Wage\n    277\n    -0.33\n    2.36\n    225\n    0.07\n    2.31\n  \n  \n    Wealth\n    277\n    -0.45\n    5.75\n    225\n    -0.60\n    5.35\n  \n  \n    Age\n    277\n    1.06\n    0.79\n    225\n    1.05\n    0.79\n  \n  \n    Years of Schooling\n    277\n    -0.05\n    2.98\n    225\n    -0.26\n    3.15\n  \n\n  \n  \n  \n    \n  \n\n\n\n\n\n\n        \n\n\nAnd you can again export descriptive statistics tables also to LaTex:\n\ndtab = pf.dtable(\n    data,\n    vars=[\"Y\", \"Y2\", \"X1\", \"X2\"],\n    labels=labels,\n    bycol=[\"country\"],\n    byrow=\"occupation\",\n    stats=[\"count\", \"mean\", \"std\"],\n    type=\"tex\",\n)\n\nrun = False\nif run:\n    make_pdf(dtab, \"latexdocs/SampleTableDoc3\")\ndisplay(FileLink(\"latexdocs/SampleTableDoc3.pdf\"))\n\nlatexdocs/SampleTableDoc3.pdf"
  },
  {
    "objectID": "table-layout.html#basic-usage-of-make_table",
    "href": "table-layout.html#basic-usage-of-make_table",
    "title": "Regression Tables via pf.etable()",
    "section": "Basic Usage of make_table",
    "text": "Basic Usage of make_table\n\ndf = pd.DataFrame(np.random.randn(4, 4).round(2), columns=[\"A\", \"B\", \"C\", \"D\"])\n\n# Make Booktabs style table\npf.make_table(df=df, caption=\"This is a caption\", notes=\"These are notes\")\n\n\n\n\n\n\n  \n    This is a caption\n  \n\n  \n  A\n  B\n  C\n  D\n\n\n\n  \n    0\n    -0.83\n    0.92\n    -1.39\n    -1.06\n  \n  \n    1\n    -0.45\n    -1.29\n    0.3\n    1.41\n  \n  \n    2\n    0.33\n    -0.17\n    0.32\n    -1.9\n  \n  \n    3\n    0.48\n    -0.74\n    -1.48\n    -1.41\n  \n\n  \n  \n  \n    These are notes"
  },
  {
    "objectID": "table-layout.html#mutiindex-dataframes",
    "href": "table-layout.html#mutiindex-dataframes",
    "title": "Regression Tables via pf.etable()",
    "section": "Mutiindex DataFrames",
    "text": "Mutiindex DataFrames\nWhen the respective dataframe has a mutiindex for the columns, columns spanners are generated from the index. The row index can also be a multiindex (of at most two levels). In this case the first index level is used to generate group rows (for instance using the index name as headline and separating the groups by a horizontal line) and the second index level is used to generate the row labels.\n\n# Create a multiindex dataframe with random data\nrow_index = pd.MultiIndex.from_tuples(\n    [\n        (\"Group 1\", \"Variable 1\"),\n        (\"Group 1\", \"Variable 2\"),\n        (\"Group 1\", \"Variable 3\"),\n        (\"Group 2\", \"Variable 4\"),\n        (\"Group 2\", \"Variable 5\"),\n        (\"Group 3\", \"Variable 6\"),\n    ]\n)\n\ncol_index = pd.MultiIndex.from_product([[\"A\", \"B\"], [\"X\", \"Y\"], [\"High\", \"Low\"]])\ndf = pd.DataFrame(np.random.randn(6, 8).round(3), index=row_index, columns=col_index)\n\npf.make_table(df=df, caption=\"This is a caption\", notes=\"These are notes\")\n\n\n\n\n\n\n  \n    This is a caption\n  \n\n  \n     \n  \n  \n    A\n  \n  \n    B\n  \n\n\n  \n  \n    X\n  \n  \n    Y\n  \n  \n    X\n  \n  \n    Y\n  \n\n\n  High\n  Low\n  High\n  Low\n  High\n  Low\n  High\n  Low\n\n\n\n  \n    Group 1\n  \n  \n    Variable 1\n    -0.42\n    -1.139\n    -0.44\n    1.629\n    1.952\n    -0.543\n    -0.015\n    0.243\n  \n  \n    Variable 2\n    0.231\n    1.805\n    -1.097\n    -0.148\n    1.344\n    -1.433\n    -0.57\n    -2.148\n  \n  \n    Variable 3\n    0.609\n    0.525\n    -0.045\n    2.377\n    -1.054\n    1.102\n    -0.219\n    -0.965\n  \n  \n    Group 2\n  \n  \n    Variable 4\n    -1.609\n    -0.012\n    1.111\n    1.686\n    0.211\n    -2.605\n    -0.723\n    -1.238\n  \n  \n    Variable 5\n    0.567\n    -0.762\n    0.253\n    0.813\n    0.905\n    -0.214\n    -1.08\n    -0.203\n  \n  \n    Group 3\n  \n  \n    Variable 6\n    0.376\n    0.294\n    -1.744\n    -0.572\n    -0.488\n    -0.813\n    0.693\n    -0.22\n  \n\n  \n  \n  \n    These are notes\n  \n\n\n\n\n\n\n        \n\n\nYou can also hide column group names: This just creates a table where variables on the second level of the row index are displayed in groups based on the first level separated by horizontal lines.\n\npf.make_table(\n    df=df, caption=\"This is a caption\", notes=\"These are notes\", rgroup_display=False\n).tab_style(style=style.text(style=\"italic\"), locations=loc.body(rows=[1, 5]))\n\n\n\n\n\n\n  \n    This is a caption\n  \n\n  \n     \n  \n  \n    A\n  \n  \n    B\n  \n\n\n  \n  \n    X\n  \n  \n    Y\n  \n  \n    X\n  \n  \n    Y\n  \n\n\n  High\n  Low\n  High\n  Low\n  High\n  Low\n  High\n  Low\n\n\n\n  \n    Group 1\n  \n  \n    Variable 1\n    -0.42\n    -1.139\n    -0.44\n    1.629\n    1.952\n    -0.543\n    -0.015\n    0.243\n  \n  \n    Variable 2\n    0.231\n    1.805\n    -1.097\n    -0.148\n    1.344\n    -1.433\n    -0.57\n    -2.148\n  \n  \n    Variable 3\n    0.609\n    0.525\n    -0.045\n    2.377\n    -1.054\n    1.102\n    -0.219\n    -0.965\n  \n  \n    Group 2\n  \n  \n    Variable 4\n    -1.609\n    -0.012\n    1.111\n    1.686\n    0.211\n    -2.605\n    -0.723\n    -1.238\n  \n  \n    Variable 5\n    0.567\n    -0.762\n    0.253\n    0.813\n    0.905\n    -0.214\n    -1.08\n    -0.203\n  \n  \n    Group 3\n  \n  \n    Variable 6\n    0.376\n    0.294\n    -1.744\n    -0.572\n    -0.488\n    -0.813\n    0.693\n    -0.22\n  \n\n  \n  \n  \n    These are notes"
  },
  {
    "objectID": "table-layout.html#example-styling",
    "href": "table-layout.html#example-styling",
    "title": "Regression Tables via pf.etable()",
    "section": "Example Styling",
    "text": "Example Styling\n\n(\n    pf.etable([fit1, fit2, fit3, fit4, fit5, fit6])\n    .tab_options(\n        column_labels_background_color=\"cornsilk\",\n        stub_background_color=\"whitesmoke\",\n    )\n    .tab_style(\n        style=style.fill(color=\"mistyrose\"),\n        locations=loc.body(columns=\"(3)\", rows=[\"X2\"]),\n    )\n)\n\n\n\n\n\n\n\n  \n  \n    Y\n  \n  \n    Y2\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    X1\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    X2\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    X1:X2\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    f2\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    f1\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "table-layout.html#defining-table-styles-some-examples",
    "href": "table-layout.html#defining-table-styles-some-examples",
    "title": "Regression Tables via pf.etable()",
    "section": "Defining Table Styles: Some Examples",
    "text": "Defining Table Styles: Some Examples\nYou can easily define table styles that you can apply to all tables in your project. Just define a dictionary with the respective values for the tab options (see the Great Tables documentation) and use the style with .tab_options(**style_dict).\n\nstyle_print = {\n    \"table_font_size\": \"12px\",\n    \"heading_title_font_size\": \"12px\",\n    \"source_notes_font_size\": \"8px\",\n    \"data_row_padding\": \"3px\",\n    \"column_labels_padding\": \"3px\",\n    \"row_group_border_top_style\": \"hidden\",\n    \"table_body_border_top_style\": \"None\",\n    \"table_body_border_bottom_width\": \"1px\",\n    \"column_labels_border_top_width\": \"1px\",\n    \"table_width\": \"14cm\",\n}\n\n\nstyle_presentation = {\n    \"table_font_size\": \"16px\",\n    \"table_font_color_light\": \"white\",\n    \"table_body_border_top_style\": \"hidden\",\n    \"table_body_border_bottom_style\": \"hidden\",\n    \"heading_title_font_size\": \"18px\",\n    \"source_notes_font_size\": \"12px\",\n    \"data_row_padding\": \"3px\",\n    \"column_labels_padding\": \"6px\",\n    \"column_labels_background_color\": \"midnightblue\",\n    \"stub_background_color\": \"whitesmoke\",\n    \"row_group_background_color\": \"whitesmoke\",\n    \"table_background_color\": \"whitesmoke\",\n    \"heading_background_color\": \"white\",\n    \"source_notes_background_color\": \"white\",\n    \"column_labels_border_bottom_color\": \"white\",\n    \"column_labels_font_weight\": \"bold\",\n    \"row_group_font_weight\": \"bold\",\n    \"table_width\": \"18cm\",\n}\n\n\nt1 = pf.dtable(\n    data,\n    vars=[\"Y\", \"Y2\", \"X1\", \"X2\"],\n    stats=[\"count\", \"mean\", \"std\", \"min\", \"max\"],\n    labels=labels,\n    caption=\"Descriptive statistics\",\n)\n\nt2 = pf.etable(\n    [fit1, fit2, fit3, fit4, fit5, fit6],\n    labels=labels,\n    show_se=False,\n    felabels={\"f1\": \"Industry Fixed Effects\", \"f2\": \"Year Fixed Effects\"},\n    caption=\"Regression results\",\n)\n\n\ndisplay(t1.tab_options(**style_print))\ndisplay(t2.tab_options(**style_print))\n\n\n\n\n\n\n  \n    Descriptive statistics\n  \n\n  \n  N\n  Mean\n  Std. Dev.\n  Min\n  Max\n\n\n\n  \n    Wage\n    997\n    -0.13\n    2.31\n    -6.54\n    6.91\n  \n  \n    Wealth\n    997\n    -0.32\n    5.59\n    -16.97\n    17.16\n  \n  \n    Age\n    997\n    1.04\n    0.81\n    0.00\n    2.00\n  \n  \n    Years of Schooling\n    997\n    -0.13\n    3.05\n    -9.67\n    10.99\n  \n\n  \n  \n  \n    \n  \n\n\n\n\n\n\n        \n\n\n\n\n\n\n\n  \n    Regression results\n  \n\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year Fixed Effects\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    Industry Fixed Effects\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)\n  \n\n\n\n\n\n\n        \n\n\n\nstyle_printDouble = {\n    \"table_font_size\": \"12px\",\n    \"heading_title_font_size\": \"12px\",\n    \"source_notes_font_size\": \"8px\",\n    \"data_row_padding\": \"3px\",\n    \"column_labels_padding\": \"3px\",\n    \"table_body_border_bottom_style\": \"double\",\n    \"column_labels_border_top_style\": \"double\",\n    \"column_labels_border_bottom_width\": \"0.5px\",\n    \"row_group_border_top_style\": \"hidden\",\n    \"table_body_border_top_style\": \"None\",\n    \"table_width\": \"14cm\",\n}\ndisplay(t1.tab_options(**style_printDouble))\ndisplay(t2.tab_options(**style_printDouble))\n\n\n\n\n\n\n  \n    Descriptive statistics\n  \n\n  \n  N\n  Mean\n  Std. Dev.\n  Min\n  Max\n\n\n\n  \n    Wage\n    997\n    -0.13\n    2.31\n    -6.54\n    6.91\n  \n  \n    Wealth\n    997\n    -0.32\n    5.59\n    -16.97\n    17.16\n  \n  \n    Age\n    997\n    1.04\n    0.81\n    0.00\n    2.00\n  \n  \n    Years of Schooling\n    997\n    -0.13\n    3.05\n    -9.67\n    10.99\n  \n\n  \n  \n  \n    \n  \n\n\n\n\n\n\n        \n\n\n\n\n\n\n\n  \n    Regression results\n  \n\n  \n  \n    Wage\n  \n  \n    Wealth\n  \n\n\n  (1)\n  (2)\n  (3)\n  (4)\n  (5)\n  (6)\n\n\n\n  \n    coef\n  \n  \n    Age\n    -0.950***  (0.067)\n    -0.924***  (0.061)\n    -0.924***  (0.061)\n    -1.267***  (0.174)\n    -1.232***  (0.192)\n    -1.231***  (0.192)\n  \n  \n    Years of Schooling\n    -0.174***  (0.018)\n    -0.174***  (0.015)\n    -0.185***  (0.025)\n    -0.131**  (0.042)\n    -0.118**  (0.042)\n    -0.074  (0.104)\n  \n  \n    Age × Years of Schooling\n    \n    \n    0.011  (0.018)\n    \n    \n    -0.041  (0.081)\n  \n  \n    fe\n  \n  \n    Year Fixed Effects\n    -\n    x\n    x\n    -\n    x\n    x\n  \n  \n    Industry Fixed Effects\n    x\n    x\n    x\n    x\n    x\n    x\n  \n  \n    stats\n  \n  \n    Observations\n    997\n    997\n    997\n    998\n    998\n    998\n  \n  \n    S.E. type\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n    by: f1\n  \n  \n    R2\n    0.489\n    0.659\n    0.659\n    0.120\n    0.172\n    0.172\n  \n\n  \n  \n  \n    Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell:\nCoefficient \n (Std. Error)"
  },
  {
    "objectID": "regression_decomposition.html",
    "href": "regression_decomposition.html",
    "title": "How much do Covariates Matter?",
    "section": "",
    "text": "In regression analyses, we often wonder about “how much covariates matter?” for explaining the relationship between a target variable \\(D\\) and an outcome variable \\(Y\\).\nFor example, we might start analysing the gender wage gap with a simple regression model as log(wage) on gender. But arguably, men and women differ in many socio-economic characteristics: they might have different (average) levels of education or career experience, and they might work in different industries and select into different higher- or lower-paying industries. So which fraction of the gender wage gap can be explained by these observable characteristics?\nIn this notebook, we will compute and decompose the gender wage gab based on a subset of the PSID data set using a method commonly known as the “Gelbach Decomposition” (Gelbach, JoLE 2016).\nWe start with loading a subset of the PSID data provided by the AER R package.\n\nimport re\n\nimport pandas as pd\n\nimport pyfixest as pf\n\npsid = pd.read_csv(\n    \"https://raw.githubusercontent.com/vincentarelbundock/Rdatasets/refs/heads/master/csv/AER/PSID7682.csv\"\n)\npsid[\"experience\"] = pd.Categorical(psid[\"experience\"])\npsid[\"year\"] = pd.Categorical(psid[\"year\"])\npsid.head()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nrownames\nexperience\nweeks\noccupation\nindustry\nsouth\nsmsa\nmarried\ngender\nunion\neducation\nethnicity\nwage\nyear\nid\n\n\n\n\n0\n1\n3\n32\nwhite\nno\nyes\nno\nyes\nmale\nno\n9\nother\n260\n1976\n1\n\n\n1\n2\n4\n43\nwhite\nno\nyes\nno\nyes\nmale\nno\n9\nother\n305\n1977\n1\n\n\n2\n3\n5\n40\nwhite\nno\nyes\nno\nyes\nmale\nno\n9\nother\n402\n1978\n1\n\n\n3\n4\n6\n39\nwhite\nno\nyes\nno\nyes\nmale\nno\n9\nother\n402\n1979\n1\n\n\n4\n5\n7\n42\nwhite\nyes\nyes\nno\nyes\nmale\nno\n9\nother\n429\n1980\n1\n\n\n\n\n\n\n\nComputing a first correlation between gender and wage, we find that males earn on average 0.474 log points more than women.\n\nfit_base = pf.feols(\"log(wage) ~ gender\", data=psid, vcov=\"hetero\")\nfit_base.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: log(wage), Fixed effects: 0\nInference:  hetero\nObservations:  4165\n\n| Coefficient    |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:---------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept      |      6.255 |        0.020 |   320.714 |      0.000 |  6.217 |   6.294 |\n| gender[T.male] |      0.474 |        0.021 |    22.818 |      0.000 |  0.434 |   0.515 |\n---\nRMSE: 0.436 R2: 0.106 \n\n\nTo examine the impact of observable on the relationship between wage and gender, a common strategy in applied research is to incrementally add a set of covariates to the baseline regression model of log(wage) on gender. Here, we will incrementally add the following covariates:\n\neducation,\nexperience\noccupation,\nindustry\nyear\nethnicity\n\nWe can do so by using multiple estimation syntax:\n\nfit_stepwise1 = pf.feols(\n    \"log(wage) ~ gender + csw0(education, experience, occupation, industry, year, ethnicity)\",\n    data=psid,\n)\npf.etable(fit_stepwise1)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlog(wage)\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n\n\n\n\ncoef\n\n\ngender[T.male]\n0.474***\n(0.021)\n0.474***\n(0.019)\n0.425***\n(0.018)\n0.444***\n(0.018)\n0.428***\n(0.018)\n0.432***\n(0.016)\n0.410***\n(0.017)\n\n\neducation\n\n0.065***\n(0.002)\n0.075***\n(0.002)\n0.061***\n(0.003)\n0.063***\n(0.003)\n0.060***\n(0.002)\n0.059***\n(0.002)\n\n\nexperience[T.2]\n\n\n0.147\n(0.156)\n0.156\n(0.155)\n0.158\n(0.154)\n0.124\n(0.137)\n0.128\n(0.136)\n\n\nexperience[T.3]\n\n\n0.273\n(0.139)\n0.284*\n(0.138)\n0.278*\n(0.138)\n0.232\n(0.122)\n0.241*\n(0.122)\n\n\nexperience[T.4]\n\n\n0.377**\n(0.137)\n0.389**\n(0.136)\n0.385**\n(0.135)\n0.287*\n(0.121)\n0.298*\n(0.120)\n\n\nexperience[T.5]\n\n\n0.452***\n(0.135)\n0.461***\n(0.134)\n0.456***\n(0.133)\n0.311**\n(0.119)\n0.323**\n(0.118)\n\n\nexperience[T.6]\n\n\n0.483***\n(0.134)\n0.495***\n(0.133)\n0.491***\n(0.132)\n0.300*\n(0.118)\n0.312**\n(0.118)\n\n\nexperience[T.7]\n\n\n0.591***\n(0.133)\n0.604***\n(0.132)\n0.599***\n(0.132)\n0.374**\n(0.118)\n0.386***\n(0.117)\n\n\nexperience[T.8]\n\n\n0.624***\n(0.133)\n0.641***\n(0.132)\n0.637***\n(0.131)\n0.387***\n(0.117)\n0.400***\n(0.117)\n\n\nexperience[T.9]\n\n\n0.667***\n(0.133)\n0.683***\n(0.132)\n0.679***\n(0.131)\n0.386**\n(0.117)\n0.399***\n(0.117)\n\n\nexperience[T.10]\n\n\n0.632***\n(0.133)\n0.646***\n(0.132)\n0.641***\n(0.131)\n0.380**\n(0.117)\n0.394***\n(0.117)\n\n\nexperience[T.11]\n\n\n0.673***\n(0.133)\n0.688***\n(0.132)\n0.681***\n(0.131)\n0.400***\n(0.117)\n0.415***\n(0.117)\n\n\nexperience[T.12]\n\n\n0.689***\n(0.133)\n0.703***\n(0.132)\n0.697***\n(0.131)\n0.412***\n(0.117)\n0.428***\n(0.117)\n\n\nexperience[T.13]\n\n\n0.750***\n(0.133)\n0.760***\n(0.132)\n0.753***\n(0.131)\n0.453***\n(0.118)\n0.470***\n(0.117)\n\n\nexperience[T.14]\n\n\n0.744***\n(0.133)\n0.753***\n(0.132)\n0.745***\n(0.132)\n0.452***\n(0.118)\n0.467***\n(0.117)\n\n\nexperience[T.15]\n\n\n0.770***\n(0.133)\n0.780***\n(0.132)\n0.771***\n(0.132)\n0.483***\n(0.118)\n0.497***\n(0.117)\n\n\nexperience[T.16]\n\n\n0.808***\n(0.134)\n0.818***\n(0.132)\n0.809***\n(0.132)\n0.498***\n(0.118)\n0.514***\n(0.117)\n\n\nexperience[T.17]\n\n\n0.803***\n(0.134)\n0.807***\n(0.133)\n0.799***\n(0.133)\n0.500***\n(0.119)\n0.517***\n(0.118)\n\n\nexperience[T.18]\n\n\n0.829***\n(0.134)\n0.833***\n(0.133)\n0.825***\n(0.133)\n0.516***\n(0.119)\n0.530***\n(0.118)\n\n\nexperience[T.19]\n\n\n0.866***\n(0.135)\n0.872***\n(0.134)\n0.860***\n(0.133)\n0.550***\n(0.119)\n0.563***\n(0.119)\n\n\nexperience[T.20]\n\n\n0.820***\n(0.135)\n0.826***\n(0.134)\n0.813***\n(0.134)\n0.514***\n(0.119)\n0.530***\n(0.119)\n\n\nexperience[T.21]\n\n\n0.828***\n(0.135)\n0.836***\n(0.134)\n0.828***\n(0.134)\n0.545***\n(0.120)\n0.564***\n(0.119)\n\n\nexperience[T.22]\n\n\n0.834***\n(0.136)\n0.836***\n(0.135)\n0.827***\n(0.134)\n0.556***\n(0.120)\n0.574***\n(0.119)\n\n\nexperience[T.23]\n\n\n0.823***\n(0.136)\n0.825***\n(0.135)\n0.815***\n(0.134)\n0.549***\n(0.120)\n0.567***\n(0.119)\n\n\nexperience[T.24]\n\n\n0.834***\n(0.136)\n0.839***\n(0.135)\n0.828***\n(0.134)\n0.552***\n(0.120)\n0.569***\n(0.119)\n\n\nexperience[T.25]\n\n\n0.876***\n(0.135)\n0.884***\n(0.134)\n0.874***\n(0.134)\n0.616***\n(0.120)\n0.633***\n(0.119)\n\n\nexperience[T.26]\n\n\n0.898***\n(0.135)\n0.911***\n(0.134)\n0.899***\n(0.134)\n0.620***\n(0.120)\n0.636***\n(0.119)\n\n\nexperience[T.27]\n\n\n0.901***\n(0.135)\n0.909***\n(0.134)\n0.897***\n(0.134)\n0.631***\n(0.120)\n0.644***\n(0.119)\n\n\nexperience[T.28]\n\n\n0.867***\n(0.135)\n0.874***\n(0.134)\n0.860***\n(0.134)\n0.601***\n(0.120)\n0.613***\n(0.119)\n\n\nexperience[T.29]\n\n\n0.897***\n(0.135)\n0.902***\n(0.134)\n0.888***\n(0.134)\n0.615***\n(0.120)\n0.629***\n(0.119)\n\n\nexperience[T.30]\n\n\n0.878***\n(0.135)\n0.886***\n(0.134)\n0.871***\n(0.133)\n0.609***\n(0.119)\n0.622***\n(0.119)\n\n\nexperience[T.31]\n\n\n0.928***\n(0.135)\n0.926***\n(0.134)\n0.911***\n(0.133)\n0.644***\n(0.119)\n0.658***\n(0.118)\n\n\nexperience[T.32]\n\n\n0.936***\n(0.135)\n0.935***\n(0.134)\n0.921***\n(0.134)\n0.648***\n(0.120)\n0.660***\n(0.119)\n\n\nexperience[T.33]\n\n\n0.970***\n(0.135)\n0.962***\n(0.134)\n0.947***\n(0.134)\n0.642***\n(0.120)\n0.655***\n(0.119)\n\n\nexperience[T.34]\n\n\n0.942***\n(0.136)\n0.938***\n(0.134)\n0.926***\n(0.134)\n0.629***\n(0.120)\n0.643***\n(0.119)\n\n\nexperience[T.35]\n\n\n0.960***\n(0.136)\n0.953***\n(0.135)\n0.941***\n(0.134)\n0.642***\n(0.120)\n0.657***\n(0.119)\n\n\nexperience[T.36]\n\n\n1.004***\n(0.136)\n1.003***\n(0.135)\n0.991***\n(0.135)\n0.663***\n(0.120)\n0.678***\n(0.120)\n\n\nexperience[T.37]\n\n\n0.951***\n(0.137)\n0.947***\n(0.136)\n0.937***\n(0.136)\n0.623***\n(0.121)\n0.639***\n(0.121)\n\n\nexperience[T.38]\n\n\n0.895***\n(0.139)\n0.900***\n(0.138)\n0.892***\n(0.137)\n0.574***\n(0.123)\n0.591***\n(0.122)\n\n\nexperience[T.39]\n\n\n0.884***\n(0.140)\n0.892***\n(0.139)\n0.880***\n(0.138)\n0.530***\n(0.124)\n0.552***\n(0.123)\n\n\nexperience[T.40]\n\n\n0.815***\n(0.140)\n0.825***\n(0.139)\n0.812***\n(0.139)\n0.461***\n(0.124)\n0.483***\n(0.123)\n\n\nexperience[T.41]\n\n\n0.775***\n(0.144)\n0.783***\n(0.143)\n0.761***\n(0.142)\n0.397**\n(0.127)\n0.421***\n(0.127)\n\n\nexperience[T.42]\n\n\n0.827***\n(0.149)\n0.841***\n(0.148)\n0.817***\n(0.148)\n0.429**\n(0.132)\n0.455***\n(0.131)\n\n\nexperience[T.43]\n\n\n0.844***\n(0.155)\n0.871***\n(0.153)\n0.850***\n(0.153)\n0.424**\n(0.137)\n0.451***\n(0.136)\n\n\nexperience[T.44]\n\n\n0.756***\n(0.165)\n0.781***\n(0.164)\n0.758***\n(0.163)\n0.394**\n(0.146)\n0.427**\n(0.145)\n\n\nexperience[T.45]\n\n\n0.733***\n(0.171)\n0.750***\n(0.169)\n0.739***\n(0.169)\n0.383*\n(0.151)\n0.407**\n(0.150)\n\n\nexperience[T.46]\n\n\n0.751***\n(0.178)\n0.768***\n(0.177)\n0.766***\n(0.176)\n0.358*\n(0.158)\n0.373*\n(0.157)\n\n\nexperience[T.47]\n\n\n0.435\n(0.249)\n0.406\n(0.247)\n0.427\n(0.246)\n0.159\n(0.219)\n0.197\n(0.218)\n\n\nexperience[T.48]\n\n\n0.675**\n(0.249)\n0.647**\n(0.247)\n0.668**\n(0.246)\n0.317\n(0.219)\n0.355\n(0.218)\n\n\nexperience[T.49]\n\n\n1.007***\n(0.249)\n0.979***\n(0.247)\n1.000***\n(0.246)\n0.575**\n(0.219)\n0.614**\n(0.218)\n\n\nexperience[T.50]\n\n\n0.920***\n(0.249)\n0.892***\n(0.247)\n0.913***\n(0.246)\n0.408\n(0.219)\n0.448*\n(0.218)\n\n\nexperience[T.51]\n\n\n0.390\n(0.389)\n0.387\n(0.386)\n0.417\n(0.385)\n-0.121\n(0.342)\n-0.120\n(0.341)\n\n\noccupation[T.white]\n\n\n\n0.125***\n(0.015)\n0.132***\n(0.015)\n0.127***\n(0.013)\n0.123***\n(0.013)\n\n\nindustry[T.yes]\n\n\n\n\n0.064***\n(0.012)\n0.070***\n(0.011)\n0.066***\n(0.011)\n\n\nyear[T.1977]\n\n\n\n\n\n0.073***\n(0.019)\n0.072***\n(0.019)\n\n\nyear[T.1978]\n\n\n\n\n\n0.193***\n(0.019)\n0.192***\n(0.019)\n\n\nyear[T.1979]\n\n\n\n\n\n0.284***\n(0.019)\n0.282***\n(0.019)\n\n\nyear[T.1980]\n\n\n\n\n\n0.363***\n(0.019)\n0.361***\n(0.019)\n\n\nyear[T.1981]\n\n\n\n\n\n0.434***\n(0.019)\n0.432***\n(0.019)\n\n\nyear[T.1982]\n\n\n\n\n\n0.518***\n(0.019)\n0.516***\n(0.019)\n\n\nethnicity[T.other]\n\n\n\n\n\n\n0.133***\n(0.020)\n\n\nIntercept\n6.255***\n(0.020)\n5.419***\n(0.034)\n4.566***\n(0.134)\n4.664***\n(0.133)\n4.636***\n(0.133)\n4.672***\n(0.118)\n4.570***\n(0.118)\n\n\nstats\n\n\nObservations\n4165\n4165\n4165\n4165\n4165\n4165\n4165\n\n\nS.E. type\niid\niid\niid\niid\niid\niid\niid\n\n\nR2\n0.106\n0.260\n0.376\n0.387\n0.391\n0.520\n0.525\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nBecause the table is so long that it’s hard to see anything, we restrict it to display only a few variables:\n\npf.etable(fit_stepwise1, keep=[\"gender\", \"ethnicity\", \"education\"])\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlog(wage)\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n\n\n\n\ncoef\n\n\ngender[T.male]\n0.474***\n(0.021)\n0.474***\n(0.019)\n0.425***\n(0.018)\n0.444***\n(0.018)\n0.428***\n(0.018)\n0.432***\n(0.016)\n0.410***\n(0.017)\n\n\nethnicity[T.other]\n\n\n\n\n\n\n0.133***\n(0.020)\n\n\neducation\n\n0.065***\n(0.002)\n0.075***\n(0.002)\n0.061***\n(0.003)\n0.063***\n(0.003)\n0.060***\n(0.002)\n0.059***\n(0.002)\n\n\nstats\n\n\nObservations\n4165\n4165\n4165\n4165\n4165\n4165\n4165\n\n\nS.E. type\niid\niid\niid\niid\niid\niid\niid\n\n\nR2\n0.106\n0.260\n0.376\n0.387\n0.391\n0.520\n0.525\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe see that the coefficient on gender is roughly the same in all models. Tentatively, we might already conclude that the observable characteristics in the data do not explain a large part of the gender wage gap.\nBut how much do differences in education matter? We have computed 6 additional models that contain education as a covariate. The obtained point estimates vary between \\(0.059\\) and \\(0.075\\). Which of these numbers should we report?\nAdditionally, note that while we have only computed 6 additional models with covariates, the number of possible models is much larger. If I did the math correctly, simply by additively and incrementally adding covariates, we could have computed \\(57\\) different models (not all of which would have included education as a control).\nAs it turns out, different models will lead to different point estimates. The order of incrementally adding covariates might impact our conclusion. To illustrate this, we keep the same ordering as before, but start with ethnicity as our first variable:\n\nfit_stepwise2 = pf.feols(\n    \"log(wage) ~ gender + csw0(ethnicity, education, experience, occupation, industry, year)\",\n    data=psid,\n)\npf.etable(fit_stepwise2, keep=[\"gender\", \"ethnicity\", \"education\"])\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlog(wage)\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n\n\n\n\ncoef\n\n\ngender[T.male]\n0.474***\n(0.021)\n0.436***\n(0.022)\n0.450***\n(0.020)\n0.399***\n(0.019)\n0.418***\n(0.019)\n0.404***\n(0.019)\n0.410***\n(0.017)\n\n\nethnicity[T.other]\n\n0.227***\n(0.026)\n0.141***\n(0.024)\n0.158***\n(0.023)\n0.151***\n(0.022)\n0.146***\n(0.022)\n0.133***\n(0.020)\n\n\neducation\n\n\n0.064***\n(0.002)\n0.074***\n(0.002)\n0.060***\n(0.003)\n0.062***\n(0.003)\n0.059***\n(0.002)\n\n\nstats\n\n\nObservations\n4165\n4165\n4165\n4165\n4165\n4165\n4165\n\n\nS.E. type\niid\niid\niid\niid\niid\niid\niid\n\n\nR2\n0.106\n0.121\n0.266\n0.383\n0.394\n0.397\n0.525\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe obtain 5 new coefficients on education that vary between 0.074 and 0.059.\nSo, which share of the “raw” gender wage gap can be attributed to differences in education between men and women? Should we report a statisics based on the 0.075 estimate? Or on the 0.059 estimate? Which value should we pick?\nTo help us with this problem, Gelbach (2016, JoLE) develops a decomposition procedure building on the omitted variable bias formula that produces a single value for the contribution of a given covariate, say education, to the gender wage gap."
  },
  {
    "objectID": "regression_decomposition.html#motivation",
    "href": "regression_decomposition.html#motivation",
    "title": "How much do Covariates Matter?",
    "section": "",
    "text": "In regression analyses, we often wonder about “how much covariates matter?” for explaining the relationship between a target variable \\(D\\) and an outcome variable \\(Y\\).\nFor example, we might start analysing the gender wage gap with a simple regression model as log(wage) on gender. But arguably, men and women differ in many socio-economic characteristics: they might have different (average) levels of education or career experience, and they might work in different industries and select into different higher- or lower-paying industries. So which fraction of the gender wage gap can be explained by these observable characteristics?\nIn this notebook, we will compute and decompose the gender wage gab based on a subset of the PSID data set using a method commonly known as the “Gelbach Decomposition” (Gelbach, JoLE 2016).\nWe start with loading a subset of the PSID data provided by the AER R package.\n\nimport re\n\nimport pandas as pd\n\nimport pyfixest as pf\n\npsid = pd.read_csv(\n    \"https://raw.githubusercontent.com/vincentarelbundock/Rdatasets/refs/heads/master/csv/AER/PSID7682.csv\"\n)\npsid[\"experience\"] = pd.Categorical(psid[\"experience\"])\npsid[\"year\"] = pd.Categorical(psid[\"year\"])\npsid.head()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nrownames\nexperience\nweeks\noccupation\nindustry\nsouth\nsmsa\nmarried\ngender\nunion\neducation\nethnicity\nwage\nyear\nid\n\n\n\n\n0\n1\n3\n32\nwhite\nno\nyes\nno\nyes\nmale\nno\n9\nother\n260\n1976\n1\n\n\n1\n2\n4\n43\nwhite\nno\nyes\nno\nyes\nmale\nno\n9\nother\n305\n1977\n1\n\n\n2\n3\n5\n40\nwhite\nno\nyes\nno\nyes\nmale\nno\n9\nother\n402\n1978\n1\n\n\n3\n4\n6\n39\nwhite\nno\nyes\nno\nyes\nmale\nno\n9\nother\n402\n1979\n1\n\n\n4\n5\n7\n42\nwhite\nyes\nyes\nno\nyes\nmale\nno\n9\nother\n429\n1980\n1\n\n\n\n\n\n\n\nComputing a first correlation between gender and wage, we find that males earn on average 0.474 log points more than women.\n\nfit_base = pf.feols(\"log(wage) ~ gender\", data=psid, vcov=\"hetero\")\nfit_base.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: log(wage), Fixed effects: 0\nInference:  hetero\nObservations:  4165\n\n| Coefficient    |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:---------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept      |      6.255 |        0.020 |   320.714 |      0.000 |  6.217 |   6.294 |\n| gender[T.male] |      0.474 |        0.021 |    22.818 |      0.000 |  0.434 |   0.515 |\n---\nRMSE: 0.436 R2: 0.106 \n\n\nTo examine the impact of observable on the relationship between wage and gender, a common strategy in applied research is to incrementally add a set of covariates to the baseline regression model of log(wage) on gender. Here, we will incrementally add the following covariates:\n\neducation,\nexperience\noccupation,\nindustry\nyear\nethnicity\n\nWe can do so by using multiple estimation syntax:\n\nfit_stepwise1 = pf.feols(\n    \"log(wage) ~ gender + csw0(education, experience, occupation, industry, year, ethnicity)\",\n    data=psid,\n)\npf.etable(fit_stepwise1)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlog(wage)\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n\n\n\n\ncoef\n\n\ngender[T.male]\n0.474***\n(0.021)\n0.474***\n(0.019)\n0.425***\n(0.018)\n0.444***\n(0.018)\n0.428***\n(0.018)\n0.432***\n(0.016)\n0.410***\n(0.017)\n\n\neducation\n\n0.065***\n(0.002)\n0.075***\n(0.002)\n0.061***\n(0.003)\n0.063***\n(0.003)\n0.060***\n(0.002)\n0.059***\n(0.002)\n\n\nexperience[T.2]\n\n\n0.147\n(0.156)\n0.156\n(0.155)\n0.158\n(0.154)\n0.124\n(0.137)\n0.128\n(0.136)\n\n\nexperience[T.3]\n\n\n0.273\n(0.139)\n0.284*\n(0.138)\n0.278*\n(0.138)\n0.232\n(0.122)\n0.241*\n(0.122)\n\n\nexperience[T.4]\n\n\n0.377**\n(0.137)\n0.389**\n(0.136)\n0.385**\n(0.135)\n0.287*\n(0.121)\n0.298*\n(0.120)\n\n\nexperience[T.5]\n\n\n0.452***\n(0.135)\n0.461***\n(0.134)\n0.456***\n(0.133)\n0.311**\n(0.119)\n0.323**\n(0.118)\n\n\nexperience[T.6]\n\n\n0.483***\n(0.134)\n0.495***\n(0.133)\n0.491***\n(0.132)\n0.300*\n(0.118)\n0.312**\n(0.118)\n\n\nexperience[T.7]\n\n\n0.591***\n(0.133)\n0.604***\n(0.132)\n0.599***\n(0.132)\n0.374**\n(0.118)\n0.386***\n(0.117)\n\n\nexperience[T.8]\n\n\n0.624***\n(0.133)\n0.641***\n(0.132)\n0.637***\n(0.131)\n0.387***\n(0.117)\n0.400***\n(0.117)\n\n\nexperience[T.9]\n\n\n0.667***\n(0.133)\n0.683***\n(0.132)\n0.679***\n(0.131)\n0.386**\n(0.117)\n0.399***\n(0.117)\n\n\nexperience[T.10]\n\n\n0.632***\n(0.133)\n0.646***\n(0.132)\n0.641***\n(0.131)\n0.380**\n(0.117)\n0.394***\n(0.117)\n\n\nexperience[T.11]\n\n\n0.673***\n(0.133)\n0.688***\n(0.132)\n0.681***\n(0.131)\n0.400***\n(0.117)\n0.415***\n(0.117)\n\n\nexperience[T.12]\n\n\n0.689***\n(0.133)\n0.703***\n(0.132)\n0.697***\n(0.131)\n0.412***\n(0.117)\n0.428***\n(0.117)\n\n\nexperience[T.13]\n\n\n0.750***\n(0.133)\n0.760***\n(0.132)\n0.753***\n(0.131)\n0.453***\n(0.118)\n0.470***\n(0.117)\n\n\nexperience[T.14]\n\n\n0.744***\n(0.133)\n0.753***\n(0.132)\n0.745***\n(0.132)\n0.452***\n(0.118)\n0.467***\n(0.117)\n\n\nexperience[T.15]\n\n\n0.770***\n(0.133)\n0.780***\n(0.132)\n0.771***\n(0.132)\n0.483***\n(0.118)\n0.497***\n(0.117)\n\n\nexperience[T.16]\n\n\n0.808***\n(0.134)\n0.818***\n(0.132)\n0.809***\n(0.132)\n0.498***\n(0.118)\n0.514***\n(0.117)\n\n\nexperience[T.17]\n\n\n0.803***\n(0.134)\n0.807***\n(0.133)\n0.799***\n(0.133)\n0.500***\n(0.119)\n0.517***\n(0.118)\n\n\nexperience[T.18]\n\n\n0.829***\n(0.134)\n0.833***\n(0.133)\n0.825***\n(0.133)\n0.516***\n(0.119)\n0.530***\n(0.118)\n\n\nexperience[T.19]\n\n\n0.866***\n(0.135)\n0.872***\n(0.134)\n0.860***\n(0.133)\n0.550***\n(0.119)\n0.563***\n(0.119)\n\n\nexperience[T.20]\n\n\n0.820***\n(0.135)\n0.826***\n(0.134)\n0.813***\n(0.134)\n0.514***\n(0.119)\n0.530***\n(0.119)\n\n\nexperience[T.21]\n\n\n0.828***\n(0.135)\n0.836***\n(0.134)\n0.828***\n(0.134)\n0.545***\n(0.120)\n0.564***\n(0.119)\n\n\nexperience[T.22]\n\n\n0.834***\n(0.136)\n0.836***\n(0.135)\n0.827***\n(0.134)\n0.556***\n(0.120)\n0.574***\n(0.119)\n\n\nexperience[T.23]\n\n\n0.823***\n(0.136)\n0.825***\n(0.135)\n0.815***\n(0.134)\n0.549***\n(0.120)\n0.567***\n(0.119)\n\n\nexperience[T.24]\n\n\n0.834***\n(0.136)\n0.839***\n(0.135)\n0.828***\n(0.134)\n0.552***\n(0.120)\n0.569***\n(0.119)\n\n\nexperience[T.25]\n\n\n0.876***\n(0.135)\n0.884***\n(0.134)\n0.874***\n(0.134)\n0.616***\n(0.120)\n0.633***\n(0.119)\n\n\nexperience[T.26]\n\n\n0.898***\n(0.135)\n0.911***\n(0.134)\n0.899***\n(0.134)\n0.620***\n(0.120)\n0.636***\n(0.119)\n\n\nexperience[T.27]\n\n\n0.901***\n(0.135)\n0.909***\n(0.134)\n0.897***\n(0.134)\n0.631***\n(0.120)\n0.644***\n(0.119)\n\n\nexperience[T.28]\n\n\n0.867***\n(0.135)\n0.874***\n(0.134)\n0.860***\n(0.134)\n0.601***\n(0.120)\n0.613***\n(0.119)\n\n\nexperience[T.29]\n\n\n0.897***\n(0.135)\n0.902***\n(0.134)\n0.888***\n(0.134)\n0.615***\n(0.120)\n0.629***\n(0.119)\n\n\nexperience[T.30]\n\n\n0.878***\n(0.135)\n0.886***\n(0.134)\n0.871***\n(0.133)\n0.609***\n(0.119)\n0.622***\n(0.119)\n\n\nexperience[T.31]\n\n\n0.928***\n(0.135)\n0.926***\n(0.134)\n0.911***\n(0.133)\n0.644***\n(0.119)\n0.658***\n(0.118)\n\n\nexperience[T.32]\n\n\n0.936***\n(0.135)\n0.935***\n(0.134)\n0.921***\n(0.134)\n0.648***\n(0.120)\n0.660***\n(0.119)\n\n\nexperience[T.33]\n\n\n0.970***\n(0.135)\n0.962***\n(0.134)\n0.947***\n(0.134)\n0.642***\n(0.120)\n0.655***\n(0.119)\n\n\nexperience[T.34]\n\n\n0.942***\n(0.136)\n0.938***\n(0.134)\n0.926***\n(0.134)\n0.629***\n(0.120)\n0.643***\n(0.119)\n\n\nexperience[T.35]\n\n\n0.960***\n(0.136)\n0.953***\n(0.135)\n0.941***\n(0.134)\n0.642***\n(0.120)\n0.657***\n(0.119)\n\n\nexperience[T.36]\n\n\n1.004***\n(0.136)\n1.003***\n(0.135)\n0.991***\n(0.135)\n0.663***\n(0.120)\n0.678***\n(0.120)\n\n\nexperience[T.37]\n\n\n0.951***\n(0.137)\n0.947***\n(0.136)\n0.937***\n(0.136)\n0.623***\n(0.121)\n0.639***\n(0.121)\n\n\nexperience[T.38]\n\n\n0.895***\n(0.139)\n0.900***\n(0.138)\n0.892***\n(0.137)\n0.574***\n(0.123)\n0.591***\n(0.122)\n\n\nexperience[T.39]\n\n\n0.884***\n(0.140)\n0.892***\n(0.139)\n0.880***\n(0.138)\n0.530***\n(0.124)\n0.552***\n(0.123)\n\n\nexperience[T.40]\n\n\n0.815***\n(0.140)\n0.825***\n(0.139)\n0.812***\n(0.139)\n0.461***\n(0.124)\n0.483***\n(0.123)\n\n\nexperience[T.41]\n\n\n0.775***\n(0.144)\n0.783***\n(0.143)\n0.761***\n(0.142)\n0.397**\n(0.127)\n0.421***\n(0.127)\n\n\nexperience[T.42]\n\n\n0.827***\n(0.149)\n0.841***\n(0.148)\n0.817***\n(0.148)\n0.429**\n(0.132)\n0.455***\n(0.131)\n\n\nexperience[T.43]\n\n\n0.844***\n(0.155)\n0.871***\n(0.153)\n0.850***\n(0.153)\n0.424**\n(0.137)\n0.451***\n(0.136)\n\n\nexperience[T.44]\n\n\n0.756***\n(0.165)\n0.781***\n(0.164)\n0.758***\n(0.163)\n0.394**\n(0.146)\n0.427**\n(0.145)\n\n\nexperience[T.45]\n\n\n0.733***\n(0.171)\n0.750***\n(0.169)\n0.739***\n(0.169)\n0.383*\n(0.151)\n0.407**\n(0.150)\n\n\nexperience[T.46]\n\n\n0.751***\n(0.178)\n0.768***\n(0.177)\n0.766***\n(0.176)\n0.358*\n(0.158)\n0.373*\n(0.157)\n\n\nexperience[T.47]\n\n\n0.435\n(0.249)\n0.406\n(0.247)\n0.427\n(0.246)\n0.159\n(0.219)\n0.197\n(0.218)\n\n\nexperience[T.48]\n\n\n0.675**\n(0.249)\n0.647**\n(0.247)\n0.668**\n(0.246)\n0.317\n(0.219)\n0.355\n(0.218)\n\n\nexperience[T.49]\n\n\n1.007***\n(0.249)\n0.979***\n(0.247)\n1.000***\n(0.246)\n0.575**\n(0.219)\n0.614**\n(0.218)\n\n\nexperience[T.50]\n\n\n0.920***\n(0.249)\n0.892***\n(0.247)\n0.913***\n(0.246)\n0.408\n(0.219)\n0.448*\n(0.218)\n\n\nexperience[T.51]\n\n\n0.390\n(0.389)\n0.387\n(0.386)\n0.417\n(0.385)\n-0.121\n(0.342)\n-0.120\n(0.341)\n\n\noccupation[T.white]\n\n\n\n0.125***\n(0.015)\n0.132***\n(0.015)\n0.127***\n(0.013)\n0.123***\n(0.013)\n\n\nindustry[T.yes]\n\n\n\n\n0.064***\n(0.012)\n0.070***\n(0.011)\n0.066***\n(0.011)\n\n\nyear[T.1977]\n\n\n\n\n\n0.073***\n(0.019)\n0.072***\n(0.019)\n\n\nyear[T.1978]\n\n\n\n\n\n0.193***\n(0.019)\n0.192***\n(0.019)\n\n\nyear[T.1979]\n\n\n\n\n\n0.284***\n(0.019)\n0.282***\n(0.019)\n\n\nyear[T.1980]\n\n\n\n\n\n0.363***\n(0.019)\n0.361***\n(0.019)\n\n\nyear[T.1981]\n\n\n\n\n\n0.434***\n(0.019)\n0.432***\n(0.019)\n\n\nyear[T.1982]\n\n\n\n\n\n0.518***\n(0.019)\n0.516***\n(0.019)\n\n\nethnicity[T.other]\n\n\n\n\n\n\n0.133***\n(0.020)\n\n\nIntercept\n6.255***\n(0.020)\n5.419***\n(0.034)\n4.566***\n(0.134)\n4.664***\n(0.133)\n4.636***\n(0.133)\n4.672***\n(0.118)\n4.570***\n(0.118)\n\n\nstats\n\n\nObservations\n4165\n4165\n4165\n4165\n4165\n4165\n4165\n\n\nS.E. type\niid\niid\niid\niid\niid\niid\niid\n\n\nR2\n0.106\n0.260\n0.376\n0.387\n0.391\n0.520\n0.525\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nBecause the table is so long that it’s hard to see anything, we restrict it to display only a few variables:\n\npf.etable(fit_stepwise1, keep=[\"gender\", \"ethnicity\", \"education\"])\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlog(wage)\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n\n\n\n\ncoef\n\n\ngender[T.male]\n0.474***\n(0.021)\n0.474***\n(0.019)\n0.425***\n(0.018)\n0.444***\n(0.018)\n0.428***\n(0.018)\n0.432***\n(0.016)\n0.410***\n(0.017)\n\n\nethnicity[T.other]\n\n\n\n\n\n\n0.133***\n(0.020)\n\n\neducation\n\n0.065***\n(0.002)\n0.075***\n(0.002)\n0.061***\n(0.003)\n0.063***\n(0.003)\n0.060***\n(0.002)\n0.059***\n(0.002)\n\n\nstats\n\n\nObservations\n4165\n4165\n4165\n4165\n4165\n4165\n4165\n\n\nS.E. type\niid\niid\niid\niid\niid\niid\niid\n\n\nR2\n0.106\n0.260\n0.376\n0.387\n0.391\n0.520\n0.525\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe see that the coefficient on gender is roughly the same in all models. Tentatively, we might already conclude that the observable characteristics in the data do not explain a large part of the gender wage gap.\nBut how much do differences in education matter? We have computed 6 additional models that contain education as a covariate. The obtained point estimates vary between \\(0.059\\) and \\(0.075\\). Which of these numbers should we report?\nAdditionally, note that while we have only computed 6 additional models with covariates, the number of possible models is much larger. If I did the math correctly, simply by additively and incrementally adding covariates, we could have computed \\(57\\) different models (not all of which would have included education as a control).\nAs it turns out, different models will lead to different point estimates. The order of incrementally adding covariates might impact our conclusion. To illustrate this, we keep the same ordering as before, but start with ethnicity as our first variable:\n\nfit_stepwise2 = pf.feols(\n    \"log(wage) ~ gender + csw0(ethnicity, education, experience, occupation, industry, year)\",\n    data=psid,\n)\npf.etable(fit_stepwise2, keep=[\"gender\", \"ethnicity\", \"education\"])\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlog(wage)\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n\n\n\n\ncoef\n\n\ngender[T.male]\n0.474***\n(0.021)\n0.436***\n(0.022)\n0.450***\n(0.020)\n0.399***\n(0.019)\n0.418***\n(0.019)\n0.404***\n(0.019)\n0.410***\n(0.017)\n\n\nethnicity[T.other]\n\n0.227***\n(0.026)\n0.141***\n(0.024)\n0.158***\n(0.023)\n0.151***\n(0.022)\n0.146***\n(0.022)\n0.133***\n(0.020)\n\n\neducation\n\n\n0.064***\n(0.002)\n0.074***\n(0.002)\n0.060***\n(0.003)\n0.062***\n(0.003)\n0.059***\n(0.002)\n\n\nstats\n\n\nObservations\n4165\n4165\n4165\n4165\n4165\n4165\n4165\n\n\nS.E. type\niid\niid\niid\niid\niid\niid\niid\n\n\nR2\n0.106\n0.121\n0.266\n0.383\n0.394\n0.397\n0.525\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe obtain 5 new coefficients on education that vary between 0.074 and 0.059.\nSo, which share of the “raw” gender wage gap can be attributed to differences in education between men and women? Should we report a statisics based on the 0.075 estimate? Or on the 0.059 estimate? Which value should we pick?\nTo help us with this problem, Gelbach (2016, JoLE) develops a decomposition procedure building on the omitted variable bias formula that produces a single value for the contribution of a given covariate, say education, to the gender wage gap."
  },
  {
    "objectID": "regression_decomposition.html#notation-and-gelbachs-algorithm",
    "href": "regression_decomposition.html#notation-and-gelbachs-algorithm",
    "title": "How much do Covariates Matter?",
    "section": "Notation and Gelbach’s Algorithm",
    "text": "Notation and Gelbach’s Algorithm\nBefore we dive into a code example, let us first introduce the notation and Gelbach’s algorithm. We are interested in “decomposing” the effect of a variable \\(X_{1} \\in \\mathbb{R}\\) on an outcome \\(Y \\in \\mathbb{R}\\) into a part explained by covariates \\(X_{2} \\in \\mathbb{R}^{k_{2}}\\) and an unexplained part.\nThus we can specify two regression models:\n\nThe short model \\[\n      Y = X_{1} \\beta_{1} + u_{1}\n  \\]\nthe long (or full) model\n\\[\n      Y = X_{1} \\beta_{1} + X_{2} \\beta_{2} + e\n  \\]\n\nBy fitting the short regression, we obtain an estimate \\(\\hat{\\beta}_{1}\\), which we will denote as the direct effect, and by estimating the long regression, we obtain an estimate of the regression coefficients \\(\\hat{\\beta}_{2} \\in \\mathbb{R}^{k_2}\\). We will denote the estimate on \\(X_1\\) in the long regression as the full effect.\nWe can then compute the contribution of an individual covariate \\(\\hat{\\delta}_{k}\\) via the following algorithm:\n\nStep 1: we compute coefficients from \\(k_{2}\\) auxiliary regression models \\(\\hat{\\Gamma}\\) as \\[\n      \\hat{\\Gamma} = (X_{1}'X_{1})^{-1} X_{1}'X_{2}\n  \\]\nIn words, we regress the target variable \\(X_{1}\\) on each covariate in \\(X_{2}\\). In practice, we can easily do this in one line of code via scipy.linalg.lstsq().\nStep 2: We can compute the total effect explained by the covariates, which we denote by \\(\\delta\\), as\n\\[\n      \\hat{\\delta} = \\sum_{k=1}^{k_2} \\hat{\\Gamma}_{k} \\hat{\\beta}_{2,k}\n  \\]\nwhere \\(\\hat{\\Gamma}_{k}\\) are the coefficients from an auxiliary regression \\(X_1\\) on covariate \\(X_{2,k}\\) and \\(\\hat{\\beta}_{2,k}\\) is the associated estimate on \\(X_{2,k}\\) from the full model.\nThe individual contribution of covariate \\(k\\) is then defined as\n\\[\n      \\hat{\\delta}_{k} = \\hat{\\Gamma}_{k} \\hat{\\beta}_{2,k}.\n  \\]\n\nAfter having obtained \\(\\delta_{k}\\) for each auxiliary variable \\(k\\), we can easily aggregate multiple variables into a single groups of interest. For example, if \\(X_{2}\\) contains a set of dummies from industry fixed effects, we could compute the explained part of “industry” by summing over all the dummies:\n\\[\n        \\hat{\\delta}_{\\textit{industry}} = \\sum_{k \\in \\textit{industry dummies}} \\hat{\\Gamma}_{k} \\hat{\\beta}_{2,k}\n\\]"
  },
  {
    "objectID": "regression_decomposition.html#pyfixest-example",
    "href": "regression_decomposition.html#pyfixest-example",
    "title": "How much do Covariates Matter?",
    "section": "PyFixest Example",
    "text": "PyFixest Example\nTo employ Gelbach’s decomposition in pyfixest, we start with the full regression model that contains all variables of interest:\n\nfit_full = pf.feols(\n    \"log(wage) ~ gender + ethnicity + education + experience + occupation + industry +year\",\n    data=psid,\n)\n\nAfter fitting the full model, we can run the decomposition procedure by calling the decompose() method. The only required argument is to specify the target parameter, which in this case is “gender”. Inference is conducted via a non-parametric bootstrap and can optionally be turned off.\n\ngb = fit_full.decompose(param=\"gender[T.male]\", digits=5)\n\n100%|██████████| 1000/1000 [00:13&lt;00:00, 72.16it/s]\n\n\nAs before, this produces a pretty big output table that reports - the direct effect of the regression of log(wage) ~ gender - the full effect of gender on log wage using the full regression with all control variables - the explained effect as the difference between the full and direct effect - a single scalar value for the individual contributions of a covariate to overall explained effect\nFor our example at hand, the additional covariates only explain a tiny fraction of the differences in log wages between men and women - 0.064 points. Of these, around one third can be attributed to ethnicity, 0.00064 to years of eduaction, etc.\n\npf.make_table(gb)\n\n\n\n\n\n\n\n\ndirect_effect\nfull_effect\nexplained_effect\n\n\n\n\ngender[T.male]\n0.47447\n0.41034\n0.06413\n\n\n\n[0.45957, 0.50398]\n[0.39909, 0.43440]\n[0.04599, 0.10157]\n\n\nethnicity[T.other]\n\n\n0.02275\n\n\n\n\n\n[0.01928, 0.02913]\n\n\neducation\n\n\n0.00064\n\n\n\n\n\n[-0.00669, 0.00551]\n\n\nexperience[T.2]\n\n\n-0.00030\n\n\n\n\n\n[-0.00038, 0.00020]\n\n\nexperience[T.3]\n\n\n-0.00234\n\n\n\n\n\n[-0.00545, 0.00068]\n\n\nexperience[T.4]\n\n\n-0.00351\n\n\n\n\n\n[-0.00664, -0.00137]\n\n\nexperience[T.5]\n\n\n-0.00307\n\n\n\n\n\n[-0.00418, -0.00210]\n\n\nexperience[T.6]\n\n\n-0.00103\n\n\n\n\n\n[-0.00388, 0.00065]\n\n\nexperience[T.7]\n\n\n0.00000\n\n\n\n\n\n[0.00023, 0.00663]\n\n\nexperience[T.8]\n\n\n0.00184\n\n\n\n\n\n[0.00048, 0.00772]\n\n\nexperience[T.9]\n\n\n-0.00338\n\n\n\n\n\n[-0.00394, 0.00290]\n\n\nexperience[T.10]\n\n\n-0.00438\n\n\n\n\n\n[-0.00822, -0.00434]\n\n\nexperience[T.11]\n\n\n-0.00185\n\n\n\n\n\n[-0.01007, 0.00476]\n\n\nexperience[T.12]\n\n\n-0.00146\n\n\n\n\n\n[-0.00367, 0.00006]\n\n\nexperience[T.13]\n\n\n-0.00588\n\n\n\n\n\n[-0.00753, 0.00256]\n\n\nexperience[T.14]\n\n\n-0.00961\n\n\n\n\n\n[-0.01220, -0.00514]\n\n\nexperience[T.15]\n\n\n-0.00878\n\n\n\n\n\n[-0.01349, 0.00014]\n\n\nexperience[T.16]\n\n\n-0.00551\n\n\n\n\n\n[-0.01104, 0.00113]\n\n\nexperience[T.17]\n\n\n-0.00020\n\n\n\n\n\n[-0.00239, 0.00118]\n\n\nexperience[T.18]\n\n\n-0.00220\n\n\n\n\n\n[-0.00425, -0.00007]\n\n\nexperience[T.19]\n\n\n-0.00551\n\n\n\n\n\n[-0.00811, -0.00134]\n\n\nexperience[T.20]\n\n\n-0.00789\n\n\n\n\n\n[-0.01951, -0.00011]\n\n\nexperience[T.21]\n\n\n-0.00358\n\n\n\n\n\n[-0.01253, -0.00033]\n\n\nexperience[T.22]\n\n\n-0.00611\n\n\n\n\n\n[-0.01149, -0.00335]\n\n\nexperience[T.23]\n\n\n-0.00225\n\n\n\n\n\n[-0.00732, 0.00394]\n\n\nexperience[T.24]\n\n\n-0.00347\n\n\n\n\n\n[-0.00518, 0.00302]\n\n\nexperience[T.25]\n\n\n-0.00132\n\n\n\n\n\n[-0.00329, 0.00276]\n\n\nexperience[T.26]\n\n\n0.00190\n\n\n\n\n\n[0.00097, 0.01047]\n\n\nexperience[T.27]\n\n\n0.00985\n\n\n\n\n\n[0.00718, 0.01245]\n\n\nexperience[T.28]\n\n\n0.00936\n\n\n\n\n\n[0.00539, 0.00755]\n\n\nexperience[T.29]\n\n\n0.01263\n\n\n\n\n\n[0.00961, 0.01783]\n\n\nexperience[T.30]\n\n\n0.01217\n\n\n\n\n\n[0.00692, 0.01191]\n\n\nexperience[T.31]\n\n\n0.01377\n\n\n\n\n\n[0.00599, 0.01641]\n\n\nexperience[T.32]\n\n\n0.01221\n\n\n\n\n\n[0.00656, 0.01189]\n\n\nexperience[T.33]\n\n\n0.01177\n\n\n\n\n\n[0.01226, 0.01842]\n\n\nexperience[T.34]\n\n\n0.01102\n\n\n\n\n\n[0.00619, 0.01278]\n\n\nexperience[T.35]\n\n\n0.00898\n\n\n\n\n\n[0.00555, 0.01469]\n\n\nexperience[T.36]\n\n\n0.00672\n\n\n\n\n\n[0.00553, 0.00988]\n\n\nexperience[T.37]\n\n\n0.00596\n\n\n\n\n\n[0.00142, 0.01117]\n\n\nexperience[T.38]\n\n\n0.00627\n\n\n\n\n\n[0.00415, 0.00908]\n\n\nexperience[T.39]\n\n\n0.00349\n\n\n\n\n\n[-0.00051, 0.00313]\n\n\nexperience[T.40]\n\n\n0.00163\n\n\n\n\n\n[-0.00053, 0.00187]\n\n\nexperience[T.41]\n\n\n-0.00006\n\n\n\n\n\n[-0.00139, 0.00112]\n\n\nexperience[T.42]\n\n\n-0.00020\n\n\n\n\n\n[-0.00091, 0.00032]\n\n\nexperience[T.43]\n\n\n0.00015\n\n\n\n\n\n[-0.00114, 0.00126]\n\n\nexperience[T.44]\n\n\n-0.00158\n\n\n\n\n\n[-0.00234, -0.00051]\n\n\nexperience[T.45]\n\n\n-0.00172\n\n\n\n\n\n[-0.00460, -0.00008]\n\n\nexperience[T.46]\n\n\n-0.00088\n\n\n\n\n\n[-0.00109, -0.00000]\n\n\nexperience[T.47]\n\n\n-0.00031\n\n\n\n\n\n[-0.00005, 0.00129]\n\n\nexperience[T.48]\n\n\n-0.00057\n\n\n\n\n\n[0.00004, 0.00093]\n\n\nexperience[T.49]\n\n\n-0.00098\n\n\n\n\n\n[-0.00261, 0.00011]\n\n\nexperience[T.50]\n\n\n-0.00071\n\n\n\n\n\n[-0.00152, 0.00024]\n\n\nexperience[T.51]\n\n\n-0.00003\n\n\n\n\n\n[-0.00026, 0.00000]\n\n\noccupation[T.white]\n\n\n-0.01649\n\n\n\n\n\n[-0.01603, -0.01136]\n\n\nindustry[T.yes]\n\n\n0.01818\n\n\n\n\n\n[0.01259, 0.02040]\n\n\nyear[T.1977]\n\n\n-0.00000\n\n\n\n\n\n[-0.00100, 0.00019]\n\n\nyear[T.1978]\n\n\n0.00000\n\n\n\n\n\n[-0.00120, 0.00534]\n\n\nyear[T.1979]\n\n\n0.00000\n\n\n\n\n\n[-0.00835, -0.00024]\n\n\nyear[T.1980]\n\n\n0.00000\n\n\n\n\n\n[-0.00264, 0.00760]\n\n\nyear[T.1981]\n\n\n0.00000\n\n\n\n\n\n[-0.00339, 0.00949]\n\n\nyear[T.1982]\n\n\n0.00000\n\n\n\n\n\n[-0.00999, 0.01238]\n\n\n\n\n\n\n\n\n\n\n\n        \n\n\nBecause experience is a categorical variable, the table gets pretty unhandy: we produce one estimate for “each” level. Luckily, Gelbach’s decomposition allows us to group individual contributions into a single number. In the decompose() method, we can combine variables via the combine_covariates argument:\n\ngb2 = fit_full.decompose(\n    param=\"gender[T.male]\",\n    combine_covariates={\n        \"experience\": re.compile(\"experience\"),\n        \"occupation\": re.compile(\"occupation\"),\n        \"industry\": re.compile(\"industry\"),\n        \"year\": re.compile(\"year\"),\n        \"ethnicity\": re.compile(\"ethnicity\"),\n    },\n)\n\n100%|██████████| 1000/1000 [00:07&lt;00:00, 128.06it/s]\n\n\nWe now report a single value for “experience”, which explains a good chunk - around half - of the explained part of the gender wage gap.\n\npf.make_table(gb2)\n\n\n\n\n\n\n\n\ndirect_effect\nfull_effect\nexplained_effect\n\n\n\n\ngender[T.male]\n0.4745\n0.4103\n0.0635\n\n\n\n[0.4558, 0.4775]\n[0.3968, 0.4222]\n[0.0512, 0.0784]\n\n\nexperience\n\n\n0.0390\n\n\n\n\n\n[0.0378, 0.0421]\n\n\noccupation\n\n\n-0.0165\n\n\n\n\n\n[-0.0277, -0.0166]\n\n\nindustry\n\n\n0.0182\n\n\n\n\n\n[0.0170, 0.0247]\n\n\nyear\n\n\n0.0000\n\n\n\n\n\n[-0.0013, 0.0141]\n\n\nethnicity\n\n\n0.0227\n\n\n\n\n\n[0.0170, 0.0200]\n\n\n\n\n\n\n\n\n\n\n\n        \n\n\nWe can aggregate even more to “individual level” and “job” level variables:\n\ngb3 = fit_full.decompose(\n    param=\"gender[T.male]\",\n    combine_covariates={\n        \"job\": re.compile(r\".*(occupation|industry).*\"),\n        \"personal\": re.compile(r\".*(education|experience|ethnicity).*\"),\n        \"year\": re.compile(\"year\"),\n    },\n)\n\n100%|██████████| 1000/1000 [00:08&lt;00:00, 116.51it/s]\n\n\n\npf.make_table(gb3)\n\n\n\n\n\n\n\n\ndirect_effect\nfull_effect\nexplained_effect\n\n\n\n\ngender[T.male]\n0.4745\n0.4103\n0.0641\n\n\n\n[0.4511, 0.4826]\n[0.3974, 0.4057]\n[0.0536, 0.0852]\n\n\njob\n\n\n0.0017\n\n\n\n\n\n[-0.0060, 0.0044]\n\n\npersonal\n\n\n0.0624\n\n\n\n\n\n[0.0504, 0.0775]\n\n\nyear\n\n\n0.0000\n\n\n\n\n\n[-0.0101, 0.0092]"
  },
  {
    "objectID": "regression_decomposition.html#literature",
    "href": "regression_decomposition.html#literature",
    "title": "How much do Covariates Matter?",
    "section": "Literature",
    "text": "Literature\n\n“When do Covariates Matter? And Which Ones, and How Much?” by Gelbach, Jonah B. (2016), Journal of Labor Economics"
  },
  {
    "objectID": "reference/report.iplot.html",
    "href": "reference/report.iplot.html",
    "title": "report.iplot",
    "section": "",
    "text": "report.iplot(\n    models,\n    alpha=0.05,\n    figsize=None,\n    yintercept=None,\n    xintercept=None,\n    rotate_xticks=0,\n    title=None,\n    coord_flip=True,\n    keep=None,\n    drop=None,\n    exact_match=False,\n    plot_backend='lets_plot',\n    labels=None,\n    ax=None,\n    joint=None,\n    seed=None,\n)\nPlot model coefficients for variables interacted via “i()” syntax, with confidence intervals.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.iplot"
    ]
  },
  {
    "objectID": "reference/report.iplot.html#parameters",
    "href": "reference/report.iplot.html#parameters",
    "title": "report.iplot",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodels\nA supported model object (Feols, Fepois, Feiv, FixestMulti) or a list of\nFeols, Fepois & Feiv models.\nrequired\n\n\nfigsize\ntuple or None\nThe size of the figure. If None, the default size is used.\nNone\n\n\nalpha\nfloat\nThe significance level for the confidence intervals.\n0.05\n\n\nyintercept\nint or None\nThe value at which to draw a horizontal line on the plot.\nNone\n\n\nxintercept\nint or None\nThe value at which to draw a vertical line on the plot.\nNone\n\n\nrotate_xticks\nfloat\nThe angle in degrees to rotate the xticks labels. Default is 0 (no rotation).\n0\n\n\ntitle\nstr\nThe title of the plot.\nNone\n\n\ncoord_flip\nbool\nWhether to flip the coordinates of the plot. Default is True.\nTrue\n\n\nkeep\nOptional[Union[list, str]]\nThe pattern for retaining coefficient names. You can pass a string (one pattern) or a list (multiple patterns). Default is keeping all coefficients. You should use regular expressions to select coefficients. “age”, # would keep all coefficients containing age r”^tr”, # would keep all coefficients starting with tr r”\\d$“, # would keep all coefficients ending with number Output will be in the order of the patterns.\nNone\n\n\ndrop\nOptional[Union[list, str]]\nThe pattern for excluding coefficient names. You can pass a string (one pattern) or a list (multiple patterns). Syntax is the same as for keep. Default is keeping all coefficients. Parameter keep and drop can be used simultaneously.\nNone\n\n\nexact_match\nbool\nWhether to use exact match for keep and drop. Default is False. If True, the pattern will be matched exactly to the coefficient name instead of using regular expressions.\nFalse\n\n\nplot_backend\nstr\nThe plotting backend to use between “lets_plot” (default) and “matplotlib”.\n'lets_plot'\n\n\nlabels\nOptional[dict]\nA dictionary to relabel the variables. The keys are the original variable names and the values the new names. The renaming is applied after the selection of the coefficients via keep and drop.\nNone\n\n\njoint\nOptional[Union[str, bool]]\nWhether to plot simultaneous confidence bands for the coefficients. If True, simultaneous confidence bands are plotted. If False, “standard” confidence intervals are plotted. If “both”, both are plotted in one figure. Default is None, which returns the standard confidence intervals. Note that this option is not available for objects of type FixestMulti, i.e. multiple estimation.\nNone\n\n\nseed\nOptional[int]\nThe seed for the random number generator. Default is None. Only required / used when joint is True.\nNone",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.iplot"
    ]
  },
  {
    "objectID": "reference/report.iplot.html#returns",
    "href": "reference/report.iplot.html#returns",
    "title": "report.iplot",
    "section": "Returns",
    "text": "Returns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nobject\nA lets-plot figure.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.iplot"
    ]
  },
  {
    "objectID": "reference/report.iplot.html#examples",
    "href": "reference/report.iplot.html#examples",
    "title": "report.iplot",
    "section": "Examples",
    "text": "Examples\n\nimport pyfixest as pf\nfrom pyfixest.report.utils import rename_categoricals\n\ndf = pf.get_data()\nfit1 = pf.feols(\"Y ~ i(f1)\", data = df)\nfit2 = pf.feols(\"Y ~ i(f1) + X2\", data = df)\nfit3 = pf.feols(\"Y ~ i(f1) + X2 | f2\", data = df)\n\npf.iplot([fit1, fit2, fit3], labels = rename_categoricals(fit1._coefnames))\n\npf.iplot([fit1], joint = \"both\")",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.iplot"
    ]
  },
  {
    "objectID": "reference/report.dtable.html",
    "href": "reference/report.dtable.html",
    "title": "report.dtable",
    "section": "",
    "text": "report.dtable(\n    df,\n    vars,\n    stats=None,\n    bycol=None,\n    byrow=None,\n    type='gt',\n    labels=None,\n    stats_labels=None,\n    digits=2,\n    notes='',\n    counts_row_below=False,\n    hide_stats=False,\n    **kwargs,\n)\nGenerate descriptive statistics tables and create a booktab style table in the desired format (gt or tex).",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.dtable"
    ]
  },
  {
    "objectID": "reference/report.dtable.html#parameters",
    "href": "reference/report.dtable.html#parameters",
    "title": "report.dtable",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ndf\npd.DataFrame\nDataFrame containing the table to be displayed.\nrequired\n\n\nvars\nlist\nList of variables to be included in the table.\nrequired\n\n\nstats\nlist\nList of statistics to be calculated. The default is None, that sets [‘count’,‘mean’, ‘std’]. All pandas aggregation functions are supported.\nNone\n\n\nbycol\nlist\nList of variables to be used to group the data by columns. The default is None.\nNone\n\n\nbyrow\nstr\nVariable to be used to group the data by rows. The default is None.\nNone\n\n\ntype\nstr\nType of table to be created. The default is ‘gt’. Type can be ‘gt’ for great_tables, ‘tex’ for LaTeX or ‘df’ for dataframe.\n'gt'\n\n\nlabels\ndict\nDictionary containing the labels for the variables. The default is None.\nNone\n\n\nstats_labels\ndict\nDictionary containing the labels for the statistics. The default is None. The function uses a default labeling which will be replaced by the labels in the dictionary.\nNone\n\n\ndigits\nint\nNumber of decimal places to round the statistics to. The default is 2.\n2\n\n\nnotes\nstr\nTable notes to be displayed at the bottom of the table.\n''\n\n\ncounts_row_below\nbool\nWhether to display the number of observations at the bottom of the table. Will only be carried out when each var has the same number of obs and when byrow is None. The default is False\nFalse\n\n\nhide_stats\nbool\nWhether to hide the names of the statistics in the table header. When stats are hidden and the user provides no notes string the labels of the stats are listed in the table notes. The default is False.\nFalse\n\n\nkwargs\ndict\nAdditional arguments to be passed to the make_table function.\n{}",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.dtable"
    ]
  },
  {
    "objectID": "reference/report.dtable.html#returns",
    "href": "reference/report.dtable.html#returns",
    "title": "report.dtable",
    "section": "Returns",
    "text": "Returns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nA table in the specified format.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.dtable"
    ]
  },
  {
    "objectID": "reference/report.dtable.html#examples",
    "href": "reference/report.dtable.html#examples",
    "title": "report.dtable",
    "section": "Examples",
    "text": "Examples\nFor more examples, take a look at the regression tables and summary statistics vignette.\n\nimport pyfixest as pf\n\n# load data\ndf = pf.get_data()\npf.dtable(df, vars = [\"Y\", \"X1\", \"X2\", \"f1\"])\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nN\nMean\nStd. Dev.\n\n\n\n\nY\n999\n-0.13\n2.30\n\n\nX1\n999\n1.04\n0.81\n\n\nX2\n1000\n-0.13\n3.05\n\n\nf1\n999\n14.21\n8.70",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.dtable"
    ]
  },
  {
    "objectID": "reference/index.html",
    "href": "reference/index.html",
    "title": "PyFixest Function Reference",
    "section": "",
    "text": "User facing estimation functions\n\n\n\nestimation.estimation.feols\nEstimate a linear regression models with fixed effects using fixest formula syntax.\n\n\nestimation.estimation.fepois\nEstimate Poisson regression model with fixed effects using the ppmlhdfe algorithm.\n\n\nestimation.estimation.feglm\nEstimate GLM regression model with fixed effects.\n\n\ndid.estimation.did2s\nEstimate a Difference-in-Differences model using Gardner’s two-step DID2S estimator.\n\n\ndid.estimation.lpdid\nLocal projections approach to estimation.\n\n\ndid.estimation.event_study\nEstimate Event Study Model.\n\n\nestimation.bonferroni\nCompute Bonferroni adjusted p-values for multiple hypothesis testing.\n\n\nestimation.rwolf\nCompute Romano-Wolf adjusted p-values for multiple hypothesis testing.\n\n\n\n\n\n\nDetails on Methods and Attributes\n\n\n\nestimation.feols_.Feols\nNon user-facing class to estimate a linear regression via OLS.\n\n\nestimation.fepois_.Fepois\nEstimate a Poisson regression model.\n\n\nestimation.feiv_.Feiv\nNon user-facing class to estimate an IV model using a 2SLS estimator.\n\n\nestimation.feglm_.Feglm\nAbstract base class for the estimation of a fixed-effects GLM model.\n\n\nestimation.felogit_.Felogit\nClass for the estimation of a fixed-effects logit model.\n\n\nestimation.feprobit_.Feprobit\nClass for the estimation of a fixed-effects probit model.\n\n\nestimation.fegaussian_.Fegaussian\nClass for the estimation of a fixed-effects GLM with normal errors.\n\n\nestimation.feols_compressed_.FeolsCompressed\nNon-user-facing class for compressed regression with fixed effects.\n\n\n\n\n\n\nPost-Processing of Estimation Results\n\n\n\ndid.visualize.panelview\nGenerate a panel view of the treatment variable over time for each unit.\n\n\nreport.summary\nPrint a summary of estimation results for each estimated model.\n\n\nreport.etable\nCreate an esttab-like table from a list of models.\n\n\nreport.dtable\nGenerate descriptive statistics tables and create a booktab style table in\n\n\nreport.coefplot\nPlot model coefficients with confidence intervals.\n\n\nreport.iplot\nPlot model coefficients for variables interacted via “i()” syntax, with\n\n\ndid.visualize.panelview\nGenerate a panel view of the treatment variable over time for each unit.\n\n\n\n\n\n\nPyFixest internals and utilities\n\n\n\nestimation.demean\nDemean an array.\n\n\nestimation.detect_singletons\nDetect singleton fixed effects in a dataset.\n\n\nestimation.model_matrix_fixest\nCreate model matrices for fixed effects estimation.",
    "crumbs": [
      "Function Reference",
      "PyFixest Function Reference"
    ]
  },
  {
    "objectID": "reference/index.html#estimation-functions",
    "href": "reference/index.html#estimation-functions",
    "title": "PyFixest Function Reference",
    "section": "",
    "text": "User facing estimation functions\n\n\n\nestimation.estimation.feols\nEstimate a linear regression models with fixed effects using fixest formula syntax.\n\n\nestimation.estimation.fepois\nEstimate Poisson regression model with fixed effects using the ppmlhdfe algorithm.\n\n\nestimation.estimation.feglm\nEstimate GLM regression model with fixed effects.\n\n\ndid.estimation.did2s\nEstimate a Difference-in-Differences model using Gardner’s two-step DID2S estimator.\n\n\ndid.estimation.lpdid\nLocal projections approach to estimation.\n\n\ndid.estimation.event_study\nEstimate Event Study Model.\n\n\nestimation.bonferroni\nCompute Bonferroni adjusted p-values for multiple hypothesis testing.\n\n\nestimation.rwolf\nCompute Romano-Wolf adjusted p-values for multiple hypothesis testing.",
    "crumbs": [
      "Function Reference",
      "PyFixest Function Reference"
    ]
  },
  {
    "objectID": "reference/index.html#estimation-classes",
    "href": "reference/index.html#estimation-classes",
    "title": "PyFixest Function Reference",
    "section": "",
    "text": "Details on Methods and Attributes\n\n\n\nestimation.feols_.Feols\nNon user-facing class to estimate a linear regression via OLS.\n\n\nestimation.fepois_.Fepois\nEstimate a Poisson regression model.\n\n\nestimation.feiv_.Feiv\nNon user-facing class to estimate an IV model using a 2SLS estimator.\n\n\nestimation.feglm_.Feglm\nAbstract base class for the estimation of a fixed-effects GLM model.\n\n\nestimation.felogit_.Felogit\nClass for the estimation of a fixed-effects logit model.\n\n\nestimation.feprobit_.Feprobit\nClass for the estimation of a fixed-effects probit model.\n\n\nestimation.fegaussian_.Fegaussian\nClass for the estimation of a fixed-effects GLM with normal errors.\n\n\nestimation.feols_compressed_.FeolsCompressed\nNon-user-facing class for compressed regression with fixed effects.",
    "crumbs": [
      "Function Reference",
      "PyFixest Function Reference"
    ]
  },
  {
    "objectID": "reference/index.html#summarize-and-visualize",
    "href": "reference/index.html#summarize-and-visualize",
    "title": "PyFixest Function Reference",
    "section": "",
    "text": "Post-Processing of Estimation Results\n\n\n\ndid.visualize.panelview\nGenerate a panel view of the treatment variable over time for each unit.\n\n\nreport.summary\nPrint a summary of estimation results for each estimated model.\n\n\nreport.etable\nCreate an esttab-like table from a list of models.\n\n\nreport.dtable\nGenerate descriptive statistics tables and create a booktab style table in\n\n\nreport.coefplot\nPlot model coefficients with confidence intervals.\n\n\nreport.iplot\nPlot model coefficients for variables interacted via “i()” syntax, with\n\n\ndid.visualize.panelview\nGenerate a panel view of the treatment variable over time for each unit.",
    "crumbs": [
      "Function Reference",
      "PyFixest Function Reference"
    ]
  },
  {
    "objectID": "reference/index.html#misc-utilities",
    "href": "reference/index.html#misc-utilities",
    "title": "PyFixest Function Reference",
    "section": "",
    "text": "PyFixest internals and utilities\n\n\n\nestimation.demean\nDemean an array.\n\n\nestimation.detect_singletons\nDetect singleton fixed effects in a dataset.\n\n\nestimation.model_matrix_fixest\nCreate model matrices for fixed effects estimation.",
    "crumbs": [
      "Function Reference",
      "PyFixest Function Reference"
    ]
  },
  {
    "objectID": "reference/estimation.model_matrix_fixest.html",
    "href": "reference/estimation.model_matrix_fixest.html",
    "title": "estimation.model_matrix_fixest",
    "section": "",
    "text": "estimation.model_matrix_fixest(\n    FixestFormula,\n    data,\n    drop_singletons=False,\n    weights=None,\n    drop_intercept=False,\n    context=0,\n)\nCreate model matrices for fixed effects estimation.\nThis function processes the data and then calls formulaic.Formula.get_model_matrix() to create the model matrices.",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.model_matrix_fixest"
    ]
  },
  {
    "objectID": "reference/estimation.model_matrix_fixest.html#parameters",
    "href": "reference/estimation.model_matrix_fixest.html#parameters",
    "title": "estimation.model_matrix_fixest",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nFixestFormula\nA pyfixest.estimation.FormulaParser.FixestFormula object\nthat contains information on the model formula, the formula of the first and second stage, dependent variable, covariates, fixed effects, endogenous variables (if any), and instruments (if any).\nrequired\n\n\ndata\npd.DataFrame\nThe input DataFrame containing the data.\nrequired\n\n\ndrop_singletons\nbool\nWhether to drop singleton fixed effects. Default is False.\nFalse\n\n\nweights\nstr or None\nA string specifying the name of the weights column in data. Default is None.\nNone\n\n\ndata\npd.DataFrame\nThe input DataFrame containing the data.\nrequired\n\n\ndrop_intercept\nbool\nWhether to drop the intercept from the model matrix. Default is False. If True, the intercept is dropped ex post from the model matrix created by formulaic.\nFalse\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\n0",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.model_matrix_fixest"
    ]
  },
  {
    "objectID": "reference/estimation.model_matrix_fixest.html#returns",
    "href": "reference/estimation.model_matrix_fixest.html#returns",
    "title": "estimation.model_matrix_fixest",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ndict\nA dictionary with the following keys and value types: - ‘Y’ : pd.DataFrame The dependent variable. - ‘X’ : pd.DataFrame The Design Matrix. - ‘fe’ : Optional[pd.DataFrame] The model’s fixed effects. None if not applicable. - ‘endogvar’ : Optional[pd.DataFrame] The model’s endogenous variable(s), None if not applicable. - ‘Z’ : np.ndarray The model’s set of instruments (exogenous covariates plus instruments). None if not applicable. - ‘weights_df’ : Optional[pd.DataFrame] DataFrame containing weights, None if weights are not used. - ‘na_index’ : np.ndarray Array indicating rows droppled beause of NA values or singleton fixed effects. - ‘na_index_str’ : str String representation of ‘na_index’. - ’_icovars’ : Optional[list[str]] List of variables interacted with i() syntax, None if not applicable. - ‘X_is_empty’ : bool Flag indicating whether X is empty.",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.model_matrix_fixest"
    ]
  },
  {
    "objectID": "reference/estimation.model_matrix_fixest.html#examples",
    "href": "reference/estimation.model_matrix_fixest.html#examples",
    "title": "estimation.model_matrix_fixest",
    "section": "Examples",
    "text": "Examples\n\nimport pyfixest as pf\nfrom pyfixest.estimation.model_matrix_fixest_ import model_matrix_fixest\n\ndata = pf.get_data()\nfit = pf.feols(\"Y ~ X1 + f1 + f2\", data=data)\nFixestFormula = fit.FixestFormula\n\nmm = model_matrix_fixest(FixestFormula, data)\nmm\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n{'Y':             Y\n 3    3.319513\n 4    0.134420\n 5   -0.278350\n 6   -1.519790\n 7   -2.072451\n ..        ...\n 995 -2.876714\n 996  1.430674\n 997 -0.494217\n 998 -1.047594\n 999  0.105551\n \n [997 rows x 1 columns],\n 'X':      Intercept   X1    f1    f2\n 3          1.0  1.0   1.0  10.0\n 4          1.0  2.0  19.0  20.0\n 5          1.0  2.0  13.0   3.0\n 6          1.0  1.0   2.0  16.0\n 7          1.0  0.0   2.0  23.0\n ..         ...  ...   ...   ...\n 995        1.0  2.0  14.0  23.0\n 996        1.0  0.0  19.0  17.0\n 997        1.0  1.0   3.0   5.0\n 998        1.0  0.0  18.0  20.0\n 999        1.0  2.0   4.0  19.0\n \n [997 rows x 4 columns],\n 'fe': None,\n 'endogvar': None,\n 'Z': None,\n 'weights_df': None,\n 'na_index': array([0, 1, 2]),\n 'na_index_str': '0,1,2',\n 'icovars': None,\n 'X_is_empty': False}",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.model_matrix_fixest"
    ]
  },
  {
    "objectID": "reference/estimation.fepois_.Fepois.html",
    "href": "reference/estimation.fepois_.Fepois.html",
    "title": "estimation.fepois_.Fepois",
    "section": "",
    "text": "estimation.fepois_.Fepois(\n    self,\n    FixestFormula,\n    data,\n    ssc_dict,\n    drop_singletons,\n    drop_intercept,\n    weights,\n    weights_type,\n    collin_tol,\n    fixef_tol,\n    lookup_demeaned_data,\n    tol,\n    maxiter,\n    solver='np.linalg.solve',\n    demeaner_backend='numba',\n    context=0,\n    store_data=True,\n    copy_data=True,\n    lean=False,\n    sample_split_var=None,\n    sample_split_value=None,\n    separation_check=None,\n)\nEstimate a Poisson regression model.\nNon user-facing class to estimate a Poisson regression model via Iterated Weighted Least Squares (IWLS).\nInherits from the Feols class. Users should not directly instantiate this class, but rather use the fepois() function. Note that no demeaning is performed in this class: demeaning is performed in the FixestMulti class (to allow for caching of demeaned variables for multiple estimation).\nThe method implements the algorithm from Stata’s ppmlhdfe module.\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n_Y\nnp.ndarray\nThe demeaned dependent variable, a two-dimensional numpy array.\n\n\n_X\nnp.ndarray\nThe demeaned independent variables, a two-dimensional numpy array.\n\n\n_fe\nnp.ndarray\nFixed effects, a two-dimensional numpy array or None.\n\n\nweights\nnp.ndarray\nWeights, a one-dimensional numpy array or None.\n\n\ncoefnames\nlist[str]\nNames of the coefficients in the design matrix X.\n\n\ndrop_singletons\nbool\nWhether to drop singleton fixed effects.\n\n\ncollin_tol\nfloat\nTolerance level for the detection of collinearity.\n\n\nmaxiter\nOptional[int], default=25\nMaximum number of iterations for the IRLS algorithm.\n\n\ntol\nOptional[float], default=1e-08\nTolerance level for the convergence of the IRLS algorithm.\n\n\nsolver\n(Literal['np.linalg.lstsq', 'np.linalg.solve', 'scipy.sparse.linalg.lsqr', 'jax'],)\ndefault is ‘np.linalg.solve’. Solver to use for the estimation.\n\n\ndemeaner_backend\nLiteral['numba', 'jax']\nThe backend used for demeaning.\n\n\nfixef_tol\nfloat, default = 1e-08.\nTolerance level for the convergence of the demeaning algorithm.\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\n\n\nweights_name\nOptional[str]\nName of the weights variable.\n\n\nweights_type\nOptional[str]\nType of weights variable.\n\n\n_data\npd.DataFrame\nThe data frame used in the estimation. None if arguments lean = True or store_data = False.\n\n\n\n\n\n\n\n\n\nName\nDescription\n\n\n\n\nget_fit\nFit a Poisson Regression Model via Iterated Weighted Least Squares (IWLS).\n\n\npredict\nReturn predicted values from regression model.\n\n\nprepare_model_matrix\nPrepare model inputs for estimation.\n\n\nresid\nReturn residuals from regression model.\n\n\nto_array\nTurn estimation DataFrames to np arrays.\n\n\n\n\n\nestimation.fepois_.Fepois.get_fit()\nFit a Poisson Regression Model via Iterated Weighted Least Squares (IWLS).\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\nbeta_hat\nnp.ndarray\nEstimated coefficients.\n\n\nY_hat\nnp.ndarray\nEstimated dependent variable.\n\n\nu_hat\nnp.ndarray\nEstimated residuals.\n\n\nweights\nnp.ndarray\nWeights (from the last iteration of the IRLS algorithm).\n\n\nX\nnp.ndarray\nDemeaned independent variables (from the last iteration of the IRLS algorithm).\n\n\nZ\nnp.ndarray\nDemeaned independent variables (from the last iteration of the IRLS algorithm).\n\n\nY\nnp.ndarray\nDemeaned dependent variable (from the last iteration of the IRLS algorithm).\n\n\n\n\n\n\n\nestimation.fepois_.Fepois.predict(\n    newdata=None,\n    atol=1e-06,\n    btol=1e-06,\n    type='link',\n)\nReturn predicted values from regression model.\nReturn a flat np.array with predicted values of the regression model. If new fixed effect levels are introduced in newdata, predicted values for such observations will be set to NaN.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nnewdata\nUnion[None, pd.DataFrame]\nA pd.DataFrame with the new data, to be used for prediction. If None (default), uses the data used for fitting the model.\nNone\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\ntype\nstr\nThe type of prediction to be computed. Can be either “response” (default) or “link”. If type=“response”, the output is at the level of the response variable, i.e., it is the expected predictor E(Y|X). If “link”, the output is at the level of the explanatory variables, i.e., the linear predictor X @ beta.\n'link'\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nA flat array with the predicted values of the regression model.\n\n\n\n\n\n\n\nestimation.fepois_.Fepois.prepare_model_matrix()\nPrepare model inputs for estimation.\n\n\n\nestimation.fepois_.Fepois.resid(type='response')\nReturn residuals from regression model.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ntype\nstr\nThe type of residuals to be computed. Can be either “response” (default) or “working”.\n'response'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nA flat array with the residuals of the regression model.\n\n\n\n\n\n\n\nestimation.fepois_.Fepois.to_array()\nTurn estimation DataFrames to np arrays.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.fepois_.Fepois"
    ]
  },
  {
    "objectID": "reference/estimation.fepois_.Fepois.html#attributes",
    "href": "reference/estimation.fepois_.Fepois.html#attributes",
    "title": "estimation.fepois_.Fepois",
    "section": "",
    "text": "Name\nType\nDescription\n\n\n\n\n_Y\nnp.ndarray\nThe demeaned dependent variable, a two-dimensional numpy array.\n\n\n_X\nnp.ndarray\nThe demeaned independent variables, a two-dimensional numpy array.\n\n\n_fe\nnp.ndarray\nFixed effects, a two-dimensional numpy array or None.\n\n\nweights\nnp.ndarray\nWeights, a one-dimensional numpy array or None.\n\n\ncoefnames\nlist[str]\nNames of the coefficients in the design matrix X.\n\n\ndrop_singletons\nbool\nWhether to drop singleton fixed effects.\n\n\ncollin_tol\nfloat\nTolerance level for the detection of collinearity.\n\n\nmaxiter\nOptional[int], default=25\nMaximum number of iterations for the IRLS algorithm.\n\n\ntol\nOptional[float], default=1e-08\nTolerance level for the convergence of the IRLS algorithm.\n\n\nsolver\n(Literal['np.linalg.lstsq', 'np.linalg.solve', 'scipy.sparse.linalg.lsqr', 'jax'],)\ndefault is ‘np.linalg.solve’. Solver to use for the estimation.\n\n\ndemeaner_backend\nLiteral['numba', 'jax']\nThe backend used for demeaning.\n\n\nfixef_tol\nfloat, default = 1e-08.\nTolerance level for the convergence of the demeaning algorithm.\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\n\n\nweights_name\nOptional[str]\nName of the weights variable.\n\n\nweights_type\nOptional[str]\nType of weights variable.\n\n\n_data\npd.DataFrame\nThe data frame used in the estimation. None if arguments lean = True or store_data = False.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.fepois_.Fepois"
    ]
  },
  {
    "objectID": "reference/estimation.fepois_.Fepois.html#methods",
    "href": "reference/estimation.fepois_.Fepois.html#methods",
    "title": "estimation.fepois_.Fepois",
    "section": "",
    "text": "Name\nDescription\n\n\n\n\nget_fit\nFit a Poisson Regression Model via Iterated Weighted Least Squares (IWLS).\n\n\npredict\nReturn predicted values from regression model.\n\n\nprepare_model_matrix\nPrepare model inputs for estimation.\n\n\nresid\nReturn residuals from regression model.\n\n\nto_array\nTurn estimation DataFrames to np arrays.\n\n\n\n\n\nestimation.fepois_.Fepois.get_fit()\nFit a Poisson Regression Model via Iterated Weighted Least Squares (IWLS).\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\nbeta_hat\nnp.ndarray\nEstimated coefficients.\n\n\nY_hat\nnp.ndarray\nEstimated dependent variable.\n\n\nu_hat\nnp.ndarray\nEstimated residuals.\n\n\nweights\nnp.ndarray\nWeights (from the last iteration of the IRLS algorithm).\n\n\nX\nnp.ndarray\nDemeaned independent variables (from the last iteration of the IRLS algorithm).\n\n\nZ\nnp.ndarray\nDemeaned independent variables (from the last iteration of the IRLS algorithm).\n\n\nY\nnp.ndarray\nDemeaned dependent variable (from the last iteration of the IRLS algorithm).\n\n\n\n\n\n\n\nestimation.fepois_.Fepois.predict(\n    newdata=None,\n    atol=1e-06,\n    btol=1e-06,\n    type='link',\n)\nReturn predicted values from regression model.\nReturn a flat np.array with predicted values of the regression model. If new fixed effect levels are introduced in newdata, predicted values for such observations will be set to NaN.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nnewdata\nUnion[None, pd.DataFrame]\nA pd.DataFrame with the new data, to be used for prediction. If None (default), uses the data used for fitting the model.\nNone\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\ntype\nstr\nThe type of prediction to be computed. Can be either “response” (default) or “link”. If type=“response”, the output is at the level of the response variable, i.e., it is the expected predictor E(Y|X). If “link”, the output is at the level of the explanatory variables, i.e., the linear predictor X @ beta.\n'link'\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nA flat array with the predicted values of the regression model.\n\n\n\n\n\n\n\nestimation.fepois_.Fepois.prepare_model_matrix()\nPrepare model inputs for estimation.\n\n\n\nestimation.fepois_.Fepois.resid(type='response')\nReturn residuals from regression model.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ntype\nstr\nThe type of residuals to be computed. Can be either “response” (default) or “working”.\n'response'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nA flat array with the residuals of the regression model.\n\n\n\n\n\n\n\nestimation.fepois_.Fepois.to_array()\nTurn estimation DataFrames to np arrays.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.fepois_.Fepois"
    ]
  },
  {
    "objectID": "reference/estimation.feols_.Feols.html",
    "href": "reference/estimation.feols_.Feols.html",
    "title": "estimation.feols_.Feols",
    "section": "",
    "text": "estimation.feols_.Feols(\n    self,\n    FixestFormula,\n    data,\n    ssc_dict,\n    drop_singletons,\n    drop_intercept,\n    weights,\n    weights_type,\n    collin_tol,\n    fixef_tol,\n    lookup_demeaned_data,\n    solver='np.linalg.solve',\n    demeaner_backend='numba',\n    store_data=True,\n    copy_data=True,\n    lean=False,\n    context=0,\n    sample_split_var=None,\n    sample_split_value=None,\n)\nNon user-facing class to estimate a linear regression via OLS.\nUsers should not directly instantiate this class, but rather use the feols() function. Note that no demeaning is performed in this class: demeaning is performed in the FixestMulti class (to allow for caching of demeaned variables for multiple estimation).",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feols_.Feols"
    ]
  },
  {
    "objectID": "reference/estimation.feols_.Feols.html#parameters",
    "href": "reference/estimation.feols_.Feols.html#parameters",
    "title": "estimation.feols_.Feols",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nY\nnp.ndarray\nDependent variable, a two-dimensional numpy array.\nrequired\n\n\nX\nnp.ndarray\nIndependent variables, a two-dimensional numpy array.\nrequired\n\n\nweights\nnp.ndarray\nWeights, a one-dimensional numpy array.\nrequired\n\n\ncollin_tol\nfloat\nTolerance level for collinearity checks.\nrequired\n\n\ncoefnames\nlist[str]\nNames of the coefficients (of the design matrix X).\nrequired\n\n\nweights_name\nOptional[str]\nName of the weights variable.\nrequired\n\n\nweights_type\nOptional[str]\nType of the weights variable. Either “aweights” for analytic weights or “fweights” for frequency weights.\nrequired\n\n\nsolver\nstr, optional.\nThe solver to use for the regression. Can be either “np.linalg.solve” or “np.linalg.lstsq”. Defaults to “np.linalg.solve”.\n'np.linalg.solve'\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\n0",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feols_.Feols"
    ]
  },
  {
    "objectID": "reference/estimation.feols_.Feols.html#attributes",
    "href": "reference/estimation.feols_.Feols.html#attributes",
    "title": "estimation.feols_.Feols",
    "section": "Attributes",
    "text": "Attributes\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n_method\nstr\nSpecifies the method used for regression, set to “feols”.\n\n\n_is_iv\nbool\nIndicates whether instrumental variables are used, initialized as False.\n\n\n_Y\nnp.ndarray\nThe demeaned dependent variable, a two-dimensional numpy array.\n\n\n_X\nnp.ndarray\nThe demeaned independent variables, a two-dimensional numpy array.\n\n\n_X_is_empty\nbool\nIndicates whether the X array is empty.\n\n\n_collin_tol\nfloat\nTolerance level for collinearity checks.\n\n\n_coefnames\nlist\nNames of the coefficients (of the design matrix X).\n\n\n_collin_vars\nlist\nVariables identified as collinear.\n\n\n_collin_index\nlist\nIndices of collinear variables.\n\n\n_Z\nnp.ndarray\nAlias for the _X array, used for calculations.\n\n\n_solver\nstr\nThe solver used for the regression.\n\n\n_weights\nnp.ndarray\nArray of weights for each observation.\n\n\n_N\nint\nNumber of observations.\n\n\n_k\nint\nNumber of independent variables (or features).\n\n\n_support_crv3_inference\nbool\nIndicates support for CRV3 inference.\n\n\n_data\nAny\nData used in the regression, to be enriched outside of the class.\n\n\n_fml\nAny\nFormula used in the regression, to be enriched outside of the class.\n\n\n_has_fixef\nbool\nIndicates whether fixed effects are used.\n\n\n_fixef\nAny\nFixed effects used in the regression.\n\n\n_icovars\nAny\nInternal covariates, to be enriched outside of the class.\n\n\n_ssc_dict\ndict\ndictionary for sum of squares and cross products matrices.\n\n\n_tZX\nnp.ndarray\nTranspose of Z multiplied by X, set in get_fit().\n\n\n_tXZ\nnp.ndarray\nTranspose of X multiplied by Z, set in get_fit().\n\n\n_tZy\nnp.ndarray\nTranspose of Z multiplied by Y, set in get_fit().\n\n\n_tZZinv\nnp.ndarray\nInverse of the transpose of Z multiplied by Z, set in get_fit().\n\n\n_beta_hat\nnp.ndarray\nEstimated regression coefficients.\n\n\n_Y_hat_link\nnp.ndarray\nPrediction at the level of the explanatory variable, i.e., the linear predictor X @ beta.\n\n\n_Y_hat_response\nnp.ndarray\nPrediction at the level of the response variable, i.e., the expected predictor E(Y|X).\n\n\n_u_hat\nnp.ndarray\nResiduals of the regression model.\n\n\n_scores\nnp.ndarray\nScores used in the regression analysis.\n\n\n_hessian\nnp.ndarray\nHessian matrix used in the regression.\n\n\n_bread\nnp.ndarray\nBread matrix, used in calculating the variance-covariance matrix.\n\n\n_vcov_type\nAny\nType of variance-covariance matrix used.\n\n\n_vcov_type_detail\nAny\nDetailed specification of the variance-covariance matrix type.\n\n\n_is_clustered\nbool\nIndicates if clustering is used in the variance-covariance calculation.\n\n\n_clustervar\nAny\nVariable used for clustering in the variance-covariance calculation.\n\n\n_G\nAny\nGroup information used in clustering.\n\n\n_ssc\nAny\nSum of squares and cross products matrix.\n\n\n_vcov\nnp.ndarray\nVariance-covariance matrix of the estimated coefficients.\n\n\n_se\nnp.ndarray\nStandard errors of the estimated coefficients.\n\n\n_tstat\nnp.ndarray\nT-statistics of the estimated coefficients.\n\n\n_pvalue\nnp.ndarray\nP-values associated with the t-statistics.\n\n\n_conf_int\nnp.ndarray\nConfidence intervals for the estimated coefficients.\n\n\n_F_stat\nAny\nF-statistic for the model, set in get_Ftest().\n\n\n_fixef_dict\ndict\ndictionary containing fixed effects estimates.\n\n\n_sumFE\nnp.ndarray\nSum of all fixed effects for each observation.\n\n\n_rmse\nfloat\nRoot mean squared error of the model.\n\n\n_r2\nfloat\nR-squared value of the model.\n\n\n_r2_within\nfloat\nR-squared value computed on demeaned dependent variable.\n\n\n_adj_r2\nfloat\nAdjusted R-squared value of the model.\n\n\n_adj_r2_within\nfloat\nAdjusted R-squared value computed on demeaned dependent variable.\n\n\n_solver\n(Literal['np.linalg.lstsq', 'np.linalg.solve', 'scipy.sparse.linalg.lsqr', 'jax'],)\ndefault is ‘np.linalg.solve’. Solver to use for the estimation.\n\n\n_demeaner_backend\nLiteral['numba', 'jax']\nThe backend used for demeaning.\n\n\n_data\npd.DataFrame\nThe data frame used in the estimation. None if arguments lean = True or store_data = False.\n\n\n_model_name\nstr\nThe name of the model. Usually just the formula string. If split estimation is used, the model name will include the split variable and value.\n\n\n_model_name_plot\nstr\nThe name of the model used when plotting and summarizing models. Usually identical to _model_name. This might be different when pf.summary() or pf.coefplot() are called and models with identical _model_name attributes are passed. In this case, the _model_name_plot attribute will be modified.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feols_.Feols"
    ]
  },
  {
    "objectID": "reference/estimation.feols_.Feols.html#methods",
    "href": "reference/estimation.feols_.Feols.html#methods",
    "title": "estimation.feols_.Feols",
    "section": "Methods",
    "text": "Methods\n\n\n\nName\nDescription\n\n\n\n\nadd_fixest_multi_context\nEnrich Feols object.\n\n\nccv\nCompute the Causal Cluster Variance following Abadie et al (QJE 2023).\n\n\ncoef\nFitted model coefficents.\n\n\nconfint\nFitted model confidence intervals.\n\n\ndecompose\nImplement the Gelbach (2016) decomposition method for mediation analysis.\n\n\ndemean\nDemean the dependent variable and covariates by the fixed effect(s).\n\n\ndrop_multicol_vars\nDetect and drop multicollinear variables.\n\n\nfixef\nCompute the coefficients of (swept out) fixed effects for a regression model.\n\n\nget_fit\nFit an OLS model.\n\n\nget_inference\nCompute standard errors, t-statistics, and p-values for the regression model.\n\n\nget_performance\nGet Goodness-of-Fit measures.\n\n\nplot_ritest\nPlot the distribution of the Randomization Inference Statistics.\n\n\npredict\nPredict values of the model on new data.\n\n\nprepare_model_matrix\nPrepare model matrices for estimation.\n\n\npvalue\nFitted model p-values.\n\n\nresid\nFitted model residuals.\n\n\nritest\nConduct Randomization Inference (RI) test against a null hypothesis of\n\n\nse\nFitted model standard errors.\n\n\ntidy\nTidy model outputs.\n\n\nto_array\nConvert estimation data frames to np arrays.\n\n\ntstat\nFitted model t-statistics.\n\n\nupdate\nUpdate coefficients for new observations using Sherman-Morrison formula.\n\n\nvcov\nCompute covariance matrices for an estimated regression model.\n\n\nwald_test\nConduct Wald test.\n\n\nwildboottest\nRun a wild cluster bootstrap based on an object of type “Feols”.\n\n\nwls_transform\nTransform model matrices for WLS Estimation.\n\n\n\n\nadd_fixest_multi_context\nestimation.feols_.Feols.add_fixest_multi_context(\n    depvar,\n    Y,\n    _data,\n    _ssc_dict,\n    _k_fe,\n    fval,\n    store_data,\n)\nEnrich Feols object.\nEnrich an instance of Feols Class with additional attributes set in the FixestMulti class.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nFixestFormula\nFixestFormula\nThe formula(s) used for estimation encoded in a FixestFormula object.\nrequired\n\n\ndepvar\nstr\nThe dependent variable of the regression model.\nrequired\n\n\nY\npd.Series\nThe dependent variable of the regression model.\nrequired\n\n\n_data\npd.DataFrame\nThe data used for estimation.\nrequired\n\n\n_ssc_dict\ndict\nA dictionary with the sum of squares and cross products matrices.\nrequired\n\n\n_k_fe\nint\nThe number of fixed effects.\nrequired\n\n\nfval\nstr\nThe fixed effects formula.\nrequired\n\n\nstore_data\nbool\nIndicates whether to save the data used for estimation in the object\nrequired\n\n\n\n\n\nReturns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\nccv\nestimation.feols_.Feols.ccv(\n    treatment,\n    cluster=None,\n    seed=None,\n    n_splits=8,\n    pk=1,\n    qk=1,\n)\nCompute the Causal Cluster Variance following Abadie et al (QJE 2023).\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ntreatment\n\nThe name of the treatment variable.\nrequired\n\n\ncluster\nstr\nThe name of the cluster variable. None by default. If None, uses the cluster variable from the model fit.\nNone\n\n\nseed\nint\nAn integer to set the random seed. Defaults to None.\nNone\n\n\nn_splits\nint\nThe number of splits to use in the cross-fitting procedure. Defaults to 8.\n8\n\n\npk\nfloat\nThe proportion of sampled clusters. Defaults to 1, which corresponds to all clusters of the population being sampled.\n1\n\n\nqk\nfloat\nThe proportion of sampled observations within each cluster. Defaults to 1, which corresponds to all observations within each cluster being sampled.\n1\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.DataFrame\nA DataFrame with inference based on the “Causal Cluster Variance” and “regular” CRV1 inference.\n\n\n\n\n\nExamples\n\nimport pyfixest as pf\nimport numpy as np\n\ndata = pf.get_data()\ndata[\"D\"] = np.random.choice([0, 1], size=data.shape[0])\n\nfit = pf.feols(\"Y ~ D\", data=data, vcov={\"CRV1\": \"group_id\"})\nfit.ccv(treatment=\"D\", pk=0.05, qk=0.5, n_splits=8, seed=123).head()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\n\n\nCCV\n-0.241099457566829\n0.206612\n-1.166916\n0.258472\n-0.675176\n0.192977\n\n\nCRV1\n-0.241099\n0.113513\n-2.123983\n0.047787\n-0.479581\n-0.002618\n\n\n\n\n\n\n\n\n\n\ncoef\nestimation.feols_.Feols.coef()\nFitted model coefficents.\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.Series\nA pd.Series with the estimated coefficients of the regression model.\n\n\n\n\n\n\nconfint\nestimation.feols_.Feols.confint(\n    alpha=0.05,\n    keep=None,\n    drop=None,\n    exact_match=False,\n    joint=False,\n    seed=None,\n    reps=10000,\n)\nFitted model confidence intervals.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nalpha\nfloat\nThe significance level for confidence intervals. Defaults to 0.05. keep: str or list of str, optional\n0.05\n\n\njoint\nbool\nWhether to compute simultaneous confidence interval for joint null of parameters selected by keep and drop. Defaults to False. See https://www.causalml-book.org/assets/chapters/CausalML_chap_4.pdf, Remark 4.4.1 for details.\nFalse\n\n\nkeep\nOptional[Union[list, str]]\nThe pattern for retaining coefficient names. You can pass a string (one pattern) or a list (multiple patterns). Default is keeping all coefficients. You should use regular expressions to select coefficients. “age”, # would keep all coefficients containing age r”^tr”, # would keep all coefficients starting with tr r”\\d$“, # would keep all coefficients ending with number Output will be in the order of the patterns.\nNone\n\n\ndrop\nOptional[Union[list, str]]\nThe pattern for excluding coefficient names. You can pass a string (one pattern) or a list (multiple patterns). Syntax is the same as for keep. Default is keeping all coefficients. Parameter keep and drop can be used simultaneously.\nNone\n\n\nexact_match\nOptional[bool]\nWhether to use exact match for keep and drop. Default is False. If True, the pattern will be matched exactly to the coefficient name instead of using regular expressions.\nFalse\n\n\nreps\nint\nThe number of bootstrap iterations to run for joint confidence intervals. Defaults to 10_000. Only used if joint is True.\n10000\n\n\nseed\nint\nThe seed for the random number generator. Defaults to None. Only used if joint is True.\nNone\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.DataFrame\nA pd.DataFrame with confidence intervals of the estimated regression model for the selected coefficients.\n\n\n\n\n\nExamples\n\nfrom pyfixest.utils import get_data\nfrom pyfixest.estimation import feols\n\ndata = get_data()\nfit = feols(\"Y ~ C(f1)\", data=data)\nfit.confint(alpha=0.10).head()\nfit.confint(alpha=0.10, joint=True, reps=9999).head()\n\n\n\n\n\n\n\n\n5.0%\n95.0%\n\n\n\n\nIntercept\n-1.363671\n0.389953\n\n\nC(f1)[T.1.0]\n1.361995\n3.726581\n\n\nC(f1)[T.2.0]\n-2.874680\n-0.394682\n\n\nC(f1)[T.3.0]\n-1.742142\n0.814181\n\n\nC(f1)[T.4.0]\n-3.011537\n-0.513887\n\n\n\n\n\n\n\n\n\n\ndecompose\nestimation.feols_.Feols.decompose(\n    param,\n    type='gelbach',\n    cluster=None,\n    combine_covariates=None,\n    reps=1000,\n    seed=None,\n    nthreads=None,\n    agg_first=None,\n    only_coef=False,\n    digits=4,\n)\nImplement the Gelbach (2016) decomposition method for mediation analysis.\nCompares a short model depvar on param with the long model specified in the original feols() call.\nFor details, take a look at “When do covariates matter?” by Gelbach (2016, JoLe). You can find an ungated version of the paper on SSRN under the following link: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1425737 .\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nparam\nstr\nThe name of the focal covariate whose effect is to be decomposed into direct and indirect components with respect to the rest of the right-hand side.\nrequired\n\n\ntype\nstr\nThe type of decomposition method to use. Defaults to “gelbach”, which currently is the only supported option.\n'gelbach'\n\n\ncluster\nOptional[str]\nThe name of the cluster variable. If None, uses the cluster variable from the model fit. Defaults to None.\nNone\n\n\ncombine_covariates\nOptional[dict[str, list[str]]]\nA dictionary that specifies which covariates to combine into groups. See the example for how to use this argument. Defaults to None.\nNone\n\n\nreps\nint\nThe number of bootstrap iterations to run. Defaults to 1000.\n1000\n\n\nseed\nint\nAn integer to set the random seed. Defaults to None.\nNone\n\n\nnthreads\nint\nThe number of threads to use for the bootstrap. Defaults to None. If None, uses all available threads minus one.\nNone\n\n\nagg_first\nbool\nIf True, use the ‘aggregate first’ algorithm described in Gelbach (2016). Recommended in cases with many (potentially high-dimensional) covariates. False by default if the ‘combine_covariates’ argument is None, True otherwise.\nNone\n\n\nonly_coef\nbool\nIndicates whether to compute inference for the decomposition. Defaults to False. If True, skips the inference step and only returns the decomposition results.\nFalse\n\n\ndigits\nint\nThe number of digits to round the results to. Defaults to 4.\n4\n\n\n\n\n\nReturns\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.DataFrame\nA DataFrame with the decomposition results.\n\n\n\n\n\nExamples\n\nimport re\nimport pyfixest as pf\nfrom pyfixest.utils.dgps import gelbach_data\n\ndata = gelbach_data(nobs = 1000)\nfit = pf.feols(\"y ~ x1 + x21 + x22 + x23\", data=data)\n\n# simple decomposition\nres = fit.decompose(param = \"x1\")\npf.make_table(res)\n\n# group covariates via \"combine_covariates\" argument\nres = fit.decompose(param = \"x1\", combine_covariates={\"g1\": [\"x21\", \"x22\"], \"g2\": [\"x23\"]})\npf.make_table(res)\n\n# group covariates via regex\nres = fit.decompose(param=\"x1\", combine_covariates={\"g1\": re.compile(\"x2[1-2]\"), \"g2\": re.compile(\"x23\")})\n\n  0%|          | 0/1000 [00:00&lt;?, ?it/s]  1%|          | 8/1000 [00:00&lt;00:24, 40.64it/s]  2%|▏         | 16/1000 [00:05&lt;06:33,  2.50it/s]  2%|▏         | 24/1000 [00:05&lt;03:41,  4.41it/s]  6%|▌         | 56/1000 [00:05&lt;01:01, 15.29it/s] 15%|█▌        | 152/1000 [00:05&lt;00:14, 58.70it/s] 41%|████      | 408/1000 [00:06&lt;00:02, 209.77it/s] 79%|███████▉  | 792/1000 [00:06&lt;00:00, 469.64it/s]100%|██████████| 1000/1000 [00:06&lt;00:00, 160.50it/s]\n  0%|          | 0/1000 [00:00&lt;?, ?it/s] 18%|█▊        | 176/1000 [00:00&lt;00:00, 1368.47it/s] 37%|███▋      | 368/1000 [00:00&lt;00:00, 1540.99it/s] 52%|█████▏    | 523/1000 [00:00&lt;00:00, 1424.12it/s] 75%|███████▌  | 752/1000 [00:00&lt;00:00, 1649.33it/s]100%|██████████| 1000/1000 [00:00&lt;00:00, 2073.05it/s]\n  0%|          | 0/1000 [00:00&lt;?, ?it/s] 11%|█         | 112/1000 [00:00&lt;00:00, 1043.87it/s] 24%|██▍       | 240/1000 [00:00&lt;00:00, 1132.11it/s] 50%|████▉     | 496/1000 [00:00&lt;00:00, 1238.62it/s] 75%|███████▌  | 752/1000 [00:00&lt;00:00, 1415.58it/s]100%|██████████| 1000/1000 [00:00&lt;00:00, 1761.31it/s]\n\n\n\n\n\ndemean\nestimation.feols_.Feols.demean()\nDemean the dependent variable and covariates by the fixed effect(s).\n\n\ndrop_multicol_vars\nestimation.feols_.Feols.drop_multicol_vars()\nDetect and drop multicollinear variables.\n\n\nfixef\nestimation.feols_.Feols.fixef(atol=1e-06, btol=1e-06)\nCompute the coefficients of (swept out) fixed effects for a regression model.\nThis method creates the following attributes: - alphaDF (pd.DataFrame): A DataFrame with the estimated fixed effects. - sumFE (np.array): An array with the sum of fixed effects for each observation (i = 1, …, N).\n\nReturns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\nget_fit\nestimation.feols_.Feols.get_fit()\nFit an OLS model.\n\nReturns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\nget_inference\nestimation.feols_.Feols.get_inference(alpha=0.05)\nCompute standard errors, t-statistics, and p-values for the regression model.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nalpha\nfloat\nThe significance level for confidence intervals. Defaults to 0.05, which produces a 95% confidence interval.\n0.05\n\n\n\n\n\nReturns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\n\n\n\nget_performance\nestimation.feols_.Feols.get_performance()\nGet Goodness-of-Fit measures.\nCompute multiple additional measures commonly reported with linear regression output, including R-squared and adjusted R-squared. Note that variables with the suffix _within use demeaned dependent variables Y, while variables without do not or are invariant to demeaning.\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone\n\n\n\n\nCreates the following instances:\n\n\n\n\n- r2 (float): R-squared of the regression model.\n\n\n\n\n- adj_r2 (float): Adjusted R-squared of the regression model.\n\n\n\n\n- r2_within (float): R-squared of the regression model, computed on\n\n\n\n\ndemeaned dependent variable.\n\n\n\n\n- adj_r2_within (float): Adjusted R-squared of the regression model,\n\n\n\n\ncomputed on demeaned dependent variable.\n\n\n\n\n\n\n\nplot_ritest\nestimation.feols_.Feols.plot_ritest(plot_backend='lets_plot')\nPlot the distribution of the Randomization Inference Statistics.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nplot_backend\nstr\nThe plotting backend to use. Defaults to “lets_plot”. Alternatively, “matplotlib” is available.\n'lets_plot'\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nA lets_plot or matplotlib figure with the distribution of the Randomization\n\n\n\n\nInference Statistics.\n\n\n\n\n\n\n\npredict\nestimation.feols_.Feols.predict(\n    newdata=None,\n    atol=1e-06,\n    btol=1e-06,\n    type='link',\n)\nPredict values of the model on new data.\nReturn a flat np.array with predicted values of the regression model. If new fixed effect levels are introduced in newdata, predicted values for such observations will be set to NaN.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nnewdata\nOptional[DataFrameType]\nA narwhals compatible DataFrame (polars, pandas, duckdb, etc). If None (default), the data used for fitting the model is used.\nNone\n\n\ntype\nstr\nThe type of prediction to be computed. Can be either “response” (default) or “link”. For linear models, both are identical.\n'link'\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nlink\n\nThe type of prediction to be made. Can be either ‘link’ or ‘response’. Defaults to ‘link’. ‘link’ and ‘response’ lead to identical results for linear models.\nrequired\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\ny_hat\nnp.ndarray\nA flat np.array with predicted values of the regression model.\n\n\n\n\n\n\nprepare_model_matrix\nestimation.feols_.Feols.prepare_model_matrix()\nPrepare model matrices for estimation.\n\n\npvalue\nestimation.feols_.Feols.pvalue()\nFitted model p-values.\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.Series\nA pd.Series with p-values of the estimated regression model.\n\n\n\n\n\n\nresid\nestimation.feols_.Feols.resid()\nFitted model residuals.\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nA np.ndarray with the residuals of the estimated regression model.\n\n\n\n\n\n\nritest\nestimation.feols_.Feols.ritest(\n    resampvar,\n    cluster=None,\n    reps=100,\n    type='randomization-c',\n    rng=None,\n    choose_algorithm='auto',\n    store_ritest_statistics=False,\n    level=0.95,\n)\nConduct Randomization Inference (RI) test against a null hypothesis of resampvar = 0.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nresampvar\nstr\nThe name of the variable to be resampled.\nrequired\n\n\ncluster\nstr\nThe name of the cluster variable in case of cluster random assignment. If provided, resampvar is held constant within each cluster. Defaults to None.\nNone\n\n\nreps\nint\nThe number of randomization iterations. Defaults to 100.\n100\n\n\ntype\nstr\nThe type of the randomization inference test. Can be “randomization-c” or “randomization-t”. Note that the “randomization-c” is much faster, while the “randomization-t” is recommended by Wu & Ding (JASA, 2021).\n'randomization-c'\n\n\nrng\nnp.random.Generator\nA random number generator. Defaults to None.\nNone\n\n\nchoose_algorithm\nstr\nThe algorithm to use for the computation. Defaults to “auto”. The alternative is “fast” and “slow”, and should only be used for running CI tests. Ironically, this argument is not tested for any input errors from the user! So please don’t use it =)\n'auto'\n\n\ninclude_plot\n\nWhether to include a plot of the distribution p-values. Defaults to False.\nrequired\n\n\nstore_ritest_statistics\nbool\nWhether to store the simulated statistics of the RI procedure. Defaults to False. If True, stores the simulated statistics in the model object via the ritest_statistics attribute as a numpy array.\nFalse\n\n\nlevel\nfloat\nThe level for the confidence interval of the randomization inference p-value. Defaults to 0.95.\n0.95\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nA pd.Series with the regression coefficient of resampvar and the p-value\n\n\n\n\nof the RI test. Additionally, reports the standard error and the confidence\n\n\n\n\ninterval of the p-value.\n\n\n\n\n\n\nExamples\n\nimport pyfixest as pf\ndata = pf.get_data()\nfit = pf.feols(\"Y ~ X1 + X2\", data=data)\n\n# Conduct a randomization inference test for the coefficient of X1\nfit.ritest(\"X1\", reps=1000)\n\n# use randomization-t instead of randomization-c\nfit.ritest(\"X1\", reps=1000, type=\"randomization-t\")\n\n# store statistics for plotting\nfit.ritest(\"X1\", reps=1000, store_ritest_statistics=True)\n\n  0%|          | 0/1000 [00:00&lt;?, ?it/s]  0%|          | 1/1000 [00:01&lt;17:50,  1.07s/it]  0%|          | 2/1000 [00:01&lt;08:28,  1.96it/s]  0%|          | 3/1000 [00:01&lt;05:28,  3.04it/s]  0%|          | 4/1000 [00:01&lt;04:02,  4.10it/s]  0%|          | 5/1000 [00:01&lt;03:17,  5.05it/s]  1%|          | 6/1000 [00:01&lt;02:47,  5.93it/s]  1%|          | 7/1000 [00:01&lt;02:29,  6.62it/s]  1%|          | 8/1000 [00:01&lt;02:17,  7.20it/s]  1%|          | 9/1000 [00:01&lt;02:09,  7.66it/s]  1%|          | 10/1000 [00:02&lt;02:03,  8.00it/s]  1%|          | 11/1000 [00:02&lt;01:59,  8.28it/s]  1%|          | 12/1000 [00:02&lt;01:56,  8.46it/s]  1%|▏         | 13/1000 [00:02&lt;01:54,  8.60it/s]  1%|▏         | 14/1000 [00:02&lt;01:56,  8.43it/s]  2%|▏         | 15/1000 [00:02&lt;01:56,  8.48it/s]  2%|▏         | 16/1000 [00:02&lt;01:55,  8.51it/s]  2%|▏         | 17/1000 [00:02&lt;01:53,  8.68it/s]  2%|▏         | 18/1000 [00:03&lt;01:52,  8.74it/s]  2%|▏         | 19/1000 [00:03&lt;01:55,  8.52it/s]  2%|▏         | 20/1000 [00:03&lt;02:00,  8.12it/s]  2%|▏         | 21/1000 [00:03&lt;02:05,  7.77it/s]  2%|▏         | 22/1000 [00:03&lt;02:10,  7.51it/s]  2%|▏         | 23/1000 [00:03&lt;02:11,  7.43it/s]  2%|▏         | 24/1000 [00:03&lt;02:07,  7.64it/s]  2%|▎         | 25/1000 [00:03&lt;02:01,  8.05it/s]  3%|▎         | 26/1000 [00:04&lt;01:57,  8.30it/s]  3%|▎         | 27/1000 [00:04&lt;01:54,  8.51it/s]  3%|▎         | 28/1000 [00:04&lt;01:52,  8.61it/s]  3%|▎         | 29/1000 [00:04&lt;01:52,  8.65it/s]  3%|▎         | 30/1000 [00:04&lt;01:52,  8.63it/s]  3%|▎         | 31/1000 [00:04&lt;01:51,  8.68it/s]  3%|▎         | 32/1000 [00:04&lt;01:50,  8.78it/s]  3%|▎         | 33/1000 [00:04&lt;01:49,  8.84it/s]  3%|▎         | 34/1000 [00:04&lt;01:48,  8.90it/s]  4%|▎         | 35/1000 [00:05&lt;01:57,  8.25it/s]  4%|▎         | 36/1000 [00:05&lt;02:02,  7.87it/s]  4%|▎         | 37/1000 [00:05&lt;02:08,  7.51it/s]  4%|▍         | 38/1000 [00:05&lt;02:03,  7.77it/s]  4%|▍         | 39/1000 [00:05&lt;01:58,  8.09it/s]  4%|▍         | 40/1000 [00:05&lt;01:55,  8.35it/s]  4%|▍         | 41/1000 [00:05&lt;01:52,  8.50it/s]  4%|▍         | 42/1000 [00:05&lt;01:51,  8.57it/s]  4%|▍         | 43/1000 [00:06&lt;02:00,  7.96it/s]  4%|▍         | 44/1000 [00:06&lt;02:11,  7.27it/s]  4%|▍         | 45/1000 [00:06&lt;02:11,  7.26it/s]  5%|▍         | 46/1000 [00:06&lt;02:03,  7.70it/s]  5%|▍         | 47/1000 [00:06&lt;01:59,  8.00it/s]  5%|▍         | 48/1000 [00:06&lt;02:03,  7.74it/s]  5%|▍         | 49/1000 [00:06&lt;02:14,  7.08it/s]  5%|▌         | 50/1000 [00:07&lt;02:09,  7.36it/s]  5%|▌         | 51/1000 [00:07&lt;02:02,  7.73it/s]  5%|▌         | 52/1000 [00:07&lt;01:59,  7.97it/s]  5%|▌         | 53/1000 [00:07&lt;01:55,  8.18it/s]  5%|▌         | 54/1000 [00:07&lt;01:52,  8.40it/s]  6%|▌         | 55/1000 [00:07&lt;01:50,  8.56it/s]  6%|▌         | 56/1000 [00:07&lt;01:56,  8.11it/s]  6%|▌         | 57/1000 [00:07&lt;02:04,  7.56it/s]  6%|▌         | 58/1000 [00:08&lt;01:58,  7.94it/s]  6%|▌         | 59/1000 [00:08&lt;01:54,  8.20it/s]  6%|▌         | 60/1000 [00:08&lt;01:52,  8.39it/s]  6%|▌         | 61/1000 [00:08&lt;01:50,  8.51it/s]  6%|▌         | 62/1000 [00:08&lt;01:49,  8.54it/s]  6%|▋         | 63/1000 [00:08&lt;01:59,  7.83it/s]  6%|▋         | 64/1000 [00:08&lt;02:05,  7.46it/s]  6%|▋         | 65/1000 [00:08&lt;02:02,  7.64it/s]  7%|▋         | 66/1000 [00:09&lt;01:57,  7.98it/s]  7%|▋         | 67/1000 [00:09&lt;01:53,  8.23it/s]  7%|▋         | 68/1000 [00:09&lt;01:56,  8.01it/s]  7%|▋         | 69/1000 [00:09&lt;01:58,  7.86it/s]  7%|▋         | 70/1000 [00:09&lt;01:53,  8.16it/s]  7%|▋         | 71/1000 [00:09&lt;01:51,  8.36it/s]  7%|▋         | 72/1000 [00:09&lt;01:49,  8.49it/s]  7%|▋         | 73/1000 [00:09&lt;01:48,  8.58it/s]  7%|▋         | 74/1000 [00:09&lt;01:46,  8.66it/s]  8%|▊         | 75/1000 [00:10&lt;01:45,  8.77it/s]  8%|▊         | 76/1000 [00:10&lt;01:45,  8.76it/s]  8%|▊         | 77/1000 [00:10&lt;01:45,  8.79it/s]  8%|▊         | 78/1000 [00:10&lt;01:44,  8.84it/s]  8%|▊         | 79/1000 [00:10&lt;01:45,  8.76it/s]  8%|▊         | 80/1000 [00:10&lt;01:44,  8.76it/s]  8%|▊         | 81/1000 [00:10&lt;01:50,  8.31it/s]  8%|▊         | 82/1000 [00:10&lt;01:58,  7.76it/s]  8%|▊         | 83/1000 [00:11&lt;02:07,  7.19it/s]  8%|▊         | 84/1000 [00:11&lt;02:07,  7.21it/s]  8%|▊         | 85/1000 [00:11&lt;02:01,  7.51it/s]  9%|▊         | 86/1000 [00:11&lt;01:56,  7.85it/s]  9%|▊         | 87/1000 [00:11&lt;02:01,  7.54it/s]  9%|▉         | 88/1000 [00:11&lt;01:57,  7.76it/s]  9%|▉         | 89/1000 [00:11&lt;01:52,  8.06it/s]  9%|▉         | 90/1000 [00:11&lt;01:55,  7.91it/s]  9%|▉         | 91/1000 [00:12&lt;02:01,  7.50it/s]  9%|▉         | 92/1000 [00:12&lt;01:55,  7.85it/s]  9%|▉         | 93/1000 [00:12&lt;01:51,  8.13it/s]  9%|▉         | 94/1000 [00:12&lt;01:49,  8.26it/s] 10%|▉         | 95/1000 [00:12&lt;01:46,  8.48it/s] 10%|▉         | 96/1000 [00:12&lt;01:52,  8.07it/s] 10%|▉         | 97/1000 [00:12&lt;01:52,  8.00it/s] 10%|▉         | 98/1000 [00:12&lt;01:58,  7.59it/s] 10%|▉         | 99/1000 [00:13&lt;01:56,  7.74it/s] 10%|█         | 100/1000 [00:13&lt;01:51,  8.10it/s] 10%|█         | 101/1000 [00:13&lt;01:48,  8.26it/s] 10%|█         | 102/1000 [00:13&lt;01:47,  8.35it/s] 10%|█         | 103/1000 [00:13&lt;01:45,  8.48it/s] 10%|█         | 104/1000 [00:13&lt;01:47,  8.34it/s] 10%|█         | 105/1000 [00:13&lt;01:55,  7.76it/s] 11%|█         | 106/1000 [00:13&lt;01:58,  7.57it/s] 11%|█         | 107/1000 [00:14&lt;01:53,  7.84it/s] 11%|█         | 108/1000 [00:14&lt;01:48,  8.21it/s] 11%|█         | 109/1000 [00:14&lt;01:46,  8.40it/s] 11%|█         | 110/1000 [00:14&lt;01:45,  8.45it/s] 11%|█         | 111/1000 [00:14&lt;01:49,  8.08it/s] 11%|█         | 112/1000 [00:14&lt;01:47,  8.27it/s] 11%|█▏        | 113/1000 [00:14&lt;01:44,  8.46it/s] 11%|█▏        | 114/1000 [00:14&lt;01:42,  8.60it/s] 12%|█▏        | 115/1000 [00:15&lt;01:42,  8.62it/s] 12%|█▏        | 116/1000 [00:15&lt;01:41,  8.70it/s] 12%|█▏        | 117/1000 [00:15&lt;01:40,  8.82it/s] 12%|█▏        | 118/1000 [00:15&lt;01:40,  8.82it/s] 12%|█▏        | 119/1000 [00:15&lt;01:39,  8.86it/s] 12%|█▏        | 120/1000 [00:15&lt;01:40,  8.80it/s] 12%|█▏        | 121/1000 [00:15&lt;01:39,  8.83it/s] 12%|█▏        | 122/1000 [00:15&lt;01:39,  8.87it/s] 12%|█▏        | 123/1000 [00:15&lt;01:39,  8.80it/s] 12%|█▏        | 124/1000 [00:16&lt;01:42,  8.54it/s] 12%|█▎        | 125/1000 [00:16&lt;01:42,  8.52it/s] 13%|█▎        | 126/1000 [00:16&lt;01:43,  8.43it/s] 13%|█▎        | 127/1000 [00:16&lt;01:41,  8.56it/s] 13%|█▎        | 128/1000 [00:16&lt;01:41,  8.63it/s] 13%|█▎        | 129/1000 [00:16&lt;01:39,  8.73it/s] 13%|█▎        | 130/1000 [00:16&lt;01:38,  8.84it/s] 13%|█▎        | 131/1000 [00:16&lt;01:38,  8.78it/s] 13%|█▎        | 132/1000 [00:16&lt;01:38,  8.80it/s] 13%|█▎        | 133/1000 [00:17&lt;01:37,  8.85it/s] 13%|█▎        | 134/1000 [00:17&lt;01:38,  8.79it/s] 14%|█▎        | 135/1000 [00:17&lt;01:38,  8.77it/s] 14%|█▎        | 136/1000 [00:17&lt;01:38,  8.75it/s] 14%|█▎        | 137/1000 [00:17&lt;01:39,  8.66it/s] 14%|█▍        | 138/1000 [00:17&lt;01:49,  7.89it/s] 14%|█▍        | 139/1000 [00:17&lt;01:52,  7.63it/s] 14%|█▍        | 140/1000 [00:17&lt;01:49,  7.84it/s] 14%|█▍        | 141/1000 [00:18&lt;01:44,  8.19it/s] 14%|█▍        | 142/1000 [00:18&lt;01:41,  8.41it/s] 14%|█▍        | 143/1000 [00:18&lt;01:40,  8.53it/s] 14%|█▍        | 144/1000 [00:18&lt;01:38,  8.65it/s] 14%|█▍        | 145/1000 [00:18&lt;01:38,  8.64it/s] 15%|█▍        | 146/1000 [00:18&lt;01:38,  8.71it/s] 15%|█▍        | 147/1000 [00:18&lt;01:39,  8.60it/s] 15%|█▍        | 148/1000 [00:18&lt;01:46,  7.97it/s] 15%|█▍        | 149/1000 [00:19&lt;01:51,  7.61it/s] 15%|█▌        | 150/1000 [00:19&lt;01:47,  7.89it/s] 15%|█▌        | 151/1000 [00:19&lt;01:44,  8.16it/s] 15%|█▌        | 152/1000 [00:19&lt;01:41,  8.34it/s] 15%|█▌        | 153/1000 [00:19&lt;01:39,  8.50it/s] 15%|█▌        | 154/1000 [00:19&lt;01:38,  8.58it/s] 16%|█▌        | 155/1000 [00:19&lt;01:36,  8.74it/s] 16%|█▌        | 156/1000 [00:19&lt;01:35,  8.80it/s] 16%|█▌        | 157/1000 [00:19&lt;01:35,  8.87it/s] 16%|█▌        | 158/1000 [00:20&lt;01:34,  8.92it/s] 16%|█▌        | 159/1000 [00:20&lt;01:33,  8.95it/s] 16%|█▌        | 160/1000 [00:20&lt;01:33,  8.95it/s] 16%|█▌        | 161/1000 [00:20&lt;01:33,  8.95it/s] 16%|█▌        | 162/1000 [00:20&lt;01:44,  8.02it/s] 16%|█▋        | 163/1000 [00:20&lt;01:45,  7.93it/s] 16%|█▋        | 164/1000 [00:20&lt;01:42,  8.15it/s] 16%|█▋        | 165/1000 [00:20&lt;01:39,  8.41it/s] 17%|█▋        | 166/1000 [00:21&lt;01:43,  8.08it/s] 17%|█▋        | 167/1000 [00:21&lt;01:41,  8.23it/s] 17%|█▋        | 168/1000 [00:21&lt;01:40,  8.32it/s] 17%|█▋        | 169/1000 [00:21&lt;01:38,  8.42it/s] 17%|█▋        | 170/1000 [00:21&lt;01:36,  8.59it/s] 17%|█▋        | 171/1000 [00:21&lt;01:35,  8.68it/s] 17%|█▋        | 172/1000 [00:21&lt;01:34,  8.73it/s] 17%|█▋        | 173/1000 [00:21&lt;01:33,  8.80it/s] 17%|█▋        | 174/1000 [00:21&lt;01:33,  8.85it/s] 18%|█▊        | 175/1000 [00:22&lt;01:33,  8.80it/s] 18%|█▊        | 176/1000 [00:22&lt;01:33,  8.85it/s] 18%|█▊        | 177/1000 [00:22&lt;01:35,  8.60it/s] 18%|█▊        | 178/1000 [00:22&lt;01:41,  8.12it/s] 18%|█▊        | 179/1000 [00:22&lt;01:39,  8.26it/s] 18%|█▊        | 180/1000 [00:22&lt;01:36,  8.46it/s] 18%|█▊        | 181/1000 [00:22&lt;01:34,  8.64it/s] 18%|█▊        | 182/1000 [00:22&lt;01:38,  8.27it/s] 18%|█▊        | 183/1000 [00:23&lt;01:45,  7.76it/s] 18%|█▊        | 184/1000 [00:23&lt;01:40,  8.08it/s] 18%|█▊        | 185/1000 [00:23&lt;01:37,  8.32it/s] 19%|█▊        | 186/1000 [00:23&lt;01:36,  8.45it/s] 19%|█▊        | 187/1000 [00:23&lt;01:40,  8.12it/s] 19%|█▉        | 188/1000 [00:23&lt;01:40,  8.09it/s] 19%|█▉        | 189/1000 [00:23&lt;01:38,  8.27it/s] 19%|█▉        | 190/1000 [00:23&lt;01:35,  8.46it/s] 19%|█▉        | 191/1000 [00:23&lt;01:34,  8.56it/s] 19%|█▉        | 192/1000 [00:24&lt;01:34,  8.54it/s] 19%|█▉        | 193/1000 [00:24&lt;01:41,  7.98it/s] 19%|█▉        | 194/1000 [00:24&lt;01:40,  8.06it/s] 20%|█▉        | 195/1000 [00:24&lt;01:38,  8.17it/s] 20%|█▉        | 196/1000 [00:24&lt;01:43,  7.77it/s] 20%|█▉        | 197/1000 [00:24&lt;01:42,  7.86it/s] 20%|█▉        | 198/1000 [00:24&lt;01:39,  8.08it/s] 20%|█▉        | 199/1000 [00:24&lt;01:36,  8.33it/s] 20%|██        | 200/1000 [00:25&lt;01:36,  8.31it/s] 20%|██        | 201/1000 [00:25&lt;01:32,  8.60it/s] 20%|██        | 202/1000 [00:25&lt;01:31,  8.75it/s] 20%|██        | 203/1000 [00:25&lt;01:37,  8.18it/s] 20%|██        | 204/1000 [00:25&lt;01:35,  8.37it/s] 20%|██        | 205/1000 [00:25&lt;01:35,  8.35it/s] 21%|██        | 206/1000 [00:25&lt;01:33,  8.50it/s] 21%|██        | 207/1000 [00:25&lt;01:32,  8.59it/s] 21%|██        | 208/1000 [00:26&lt;01:34,  8.41it/s] 21%|██        | 209/1000 [00:26&lt;01:44,  7.60it/s] 21%|██        | 210/1000 [00:26&lt;01:47,  7.36it/s] 21%|██        | 211/1000 [00:26&lt;01:42,  7.70it/s] 21%|██        | 212/1000 [00:26&lt;01:40,  7.81it/s] 21%|██▏       | 213/1000 [00:26&lt;01:44,  7.50it/s] 21%|██▏       | 214/1000 [00:26&lt;01:39,  7.86it/s] 22%|██▏       | 215/1000 [00:26&lt;01:36,  8.15it/s] 22%|██▏       | 216/1000 [00:27&lt;01:35,  8.18it/s] 22%|██▏       | 217/1000 [00:27&lt;01:48,  7.25it/s] 22%|██▏       | 218/1000 [00:27&lt;01:50,  7.08it/s] 22%|██▏       | 219/1000 [00:27&lt;01:48,  7.22it/s] 22%|██▏       | 220/1000 [00:27&lt;01:44,  7.49it/s] 22%|██▏       | 221/1000 [00:27&lt;01:40,  7.75it/s] 22%|██▏       | 222/1000 [00:27&lt;01:38,  7.89it/s] 22%|██▏       | 223/1000 [00:28&lt;01:35,  8.14it/s] 22%|██▏       | 224/1000 [00:28&lt;01:34,  8.21it/s] 22%|██▎       | 225/1000 [00:28&lt;01:32,  8.42it/s] 23%|██▎       | 226/1000 [00:28&lt;01:30,  8.53it/s] 23%|██▎       | 227/1000 [00:28&lt;01:35,  8.11it/s] 23%|██▎       | 228/1000 [00:28&lt;01:39,  7.73it/s] 23%|██▎       | 229/1000 [00:28&lt;01:43,  7.43it/s] 23%|██▎       | 230/1000 [00:28&lt;01:45,  7.27it/s] 23%|██▎       | 231/1000 [00:29&lt;01:42,  7.49it/s] 23%|██▎       | 232/1000 [00:29&lt;01:38,  7.83it/s] 23%|██▎       | 233/1000 [00:29&lt;01:40,  7.61it/s] 23%|██▎       | 234/1000 [00:29&lt;01:44,  7.36it/s] 24%|██▎       | 235/1000 [00:29&lt;01:38,  7.73it/s] 24%|██▎       | 236/1000 [00:29&lt;01:36,  7.89it/s] 24%|██▎       | 237/1000 [00:29&lt;01:40,  7.56it/s] 24%|██▍       | 238/1000 [00:29&lt;01:37,  7.84it/s] 24%|██▍       | 239/1000 [00:30&lt;01:33,  8.14it/s] 24%|██▍       | 240/1000 [00:30&lt;01:31,  8.32it/s] 24%|██▍       | 241/1000 [00:30&lt;01:29,  8.49it/s] 24%|██▍       | 242/1000 [00:30&lt;01:28,  8.58it/s] 24%|██▍       | 243/1000 [00:30&lt;01:27,  8.63it/s] 24%|██▍       | 244/1000 [00:30&lt;01:27,  8.61it/s] 24%|██▍       | 245/1000 [00:30&lt;01:27,  8.58it/s] 25%|██▍       | 246/1000 [00:30&lt;01:29,  8.44it/s] 25%|██▍       | 247/1000 [00:30&lt;01:29,  8.40it/s] 25%|██▍       | 248/1000 [00:31&lt;01:29,  8.37it/s] 25%|██▍       | 249/1000 [00:31&lt;01:32,  8.16it/s] 25%|██▌       | 250/1000 [00:31&lt;01:40,  7.46it/s] 25%|██▌       | 251/1000 [00:31&lt;01:43,  7.24it/s] 25%|██▌       | 252/1000 [00:31&lt;01:37,  7.68it/s] 25%|██▌       | 253/1000 [00:31&lt;01:33,  7.96it/s] 25%|██▌       | 254/1000 [00:31&lt;01:38,  7.56it/s] 26%|██▌       | 255/1000 [00:32&lt;01:38,  7.59it/s] 26%|██▌       | 256/1000 [00:32&lt;01:33,  8.00it/s] 26%|██▌       | 257/1000 [00:32&lt;01:30,  8.21it/s] 26%|██▌       | 258/1000 [00:32&lt;01:29,  8.31it/s] 26%|██▌       | 259/1000 [00:32&lt;01:27,  8.50it/s] 26%|██▌       | 260/1000 [00:32&lt;01:30,  8.17it/s] 26%|██▌       | 261/1000 [00:32&lt;01:30,  8.17it/s] 26%|██▌       | 262/1000 [00:32&lt;01:29,  8.28it/s] 26%|██▋       | 263/1000 [00:33&lt;01:34,  7.82it/s] 26%|██▋       | 264/1000 [00:33&lt;01:34,  7.78it/s] 26%|██▋       | 265/1000 [00:33&lt;01:30,  8.10it/s] 27%|██▋       | 266/1000 [00:33&lt;01:30,  8.12it/s] 27%|██▋       | 267/1000 [00:33&lt;01:33,  7.82it/s] 27%|██▋       | 268/1000 [00:33&lt;01:30,  8.09it/s] 27%|██▋       | 269/1000 [00:33&lt;01:28,  8.25it/s] 27%|██▋       | 270/1000 [00:33&lt;01:26,  8.40it/s] 27%|██▋       | 271/1000 [00:33&lt;01:25,  8.57it/s] 27%|██▋       | 272/1000 [00:34&lt;01:24,  8.64it/s] 27%|██▋       | 273/1000 [00:34&lt;01:24,  8.60it/s] 27%|██▋       | 274/1000 [00:34&lt;01:29,  8.12it/s] 28%|██▊       | 275/1000 [00:34&lt;01:37,  7.47it/s] 28%|██▊       | 276/1000 [00:34&lt;01:34,  7.65it/s] 28%|██▊       | 277/1000 [00:34&lt;01:29,  8.04it/s] 28%|██▊       | 278/1000 [00:34&lt;01:26,  8.30it/s] 28%|██▊       | 279/1000 [00:34&lt;01:24,  8.49it/s] 28%|██▊       | 280/1000 [00:35&lt;01:24,  8.54it/s] 28%|██▊       | 281/1000 [00:35&lt;01:23,  8.57it/s] 28%|██▊       | 282/1000 [00:35&lt;01:29,  8.04it/s] 28%|██▊       | 283/1000 [00:35&lt;01:30,  7.95it/s] 28%|██▊       | 284/1000 [00:35&lt;01:33,  7.64it/s] 28%|██▊       | 285/1000 [00:35&lt;01:32,  7.72it/s] 29%|██▊       | 286/1000 [00:35&lt;01:29,  8.02it/s] 29%|██▊       | 287/1000 [00:35&lt;01:27,  8.10it/s] 29%|██▉       | 288/1000 [00:36&lt;01:26,  8.27it/s] 29%|██▉       | 289/1000 [00:36&lt;01:30,  7.88it/s] 29%|██▉       | 290/1000 [00:36&lt;01:28,  8.01it/s] 29%|██▉       | 291/1000 [00:36&lt;01:25,  8.25it/s] 29%|██▉       | 292/1000 [00:36&lt;01:23,  8.46it/s] 29%|██▉       | 293/1000 [00:36&lt;01:21,  8.72it/s] 29%|██▉       | 294/1000 [00:36&lt;01:21,  8.66it/s] 30%|██▉       | 295/1000 [00:36&lt;01:21,  8.65it/s] 30%|██▉       | 296/1000 [00:37&lt;01:22,  8.54it/s] 30%|██▉       | 297/1000 [00:37&lt;01:21,  8.60it/s] 30%|██▉       | 298/1000 [00:37&lt;01:22,  8.46it/s] 30%|██▉       | 299/1000 [00:37&lt;01:22,  8.53it/s] 30%|███       | 300/1000 [00:37&lt;01:22,  8.50it/s] 30%|███       | 301/1000 [00:37&lt;01:20,  8.63it/s] 30%|███       | 302/1000 [00:37&lt;01:20,  8.71it/s] 30%|███       | 303/1000 [00:37&lt;01:19,  8.72it/s] 30%|███       | 304/1000 [00:37&lt;01:19,  8.74it/s] 30%|███       | 305/1000 [00:38&lt;01:18,  8.81it/s] 31%|███       | 306/1000 [00:38&lt;01:27,  7.95it/s] 31%|███       | 307/1000 [00:38&lt;01:27,  7.88it/s] 31%|███       | 308/1000 [00:38&lt;01:25,  8.06it/s] 31%|███       | 309/1000 [00:38&lt;01:23,  8.28it/s] 31%|███       | 310/1000 [00:38&lt;01:22,  8.35it/s] 31%|███       | 311/1000 [00:38&lt;01:23,  8.27it/s] 31%|███       | 312/1000 [00:38&lt;01:24,  8.17it/s] 31%|███▏      | 313/1000 [00:39&lt;01:23,  8.23it/s] 31%|███▏      | 314/1000 [00:39&lt;01:24,  8.16it/s] 32%|███▏      | 315/1000 [00:39&lt;01:48,  6.31it/s] 32%|███▏      | 316/1000 [00:39&lt;02:01,  5.62it/s] 32%|███▏      | 317/1000 [00:39&lt;01:52,  6.08it/s] 32%|███▏      | 318/1000 [00:39&lt;01:44,  6.55it/s] 32%|███▏      | 319/1000 [00:40&lt;01:39,  6.87it/s] 32%|███▏      | 320/1000 [00:40&lt;01:35,  7.15it/s] 32%|███▏      | 321/1000 [00:40&lt;01:35,  7.12it/s] 32%|███▏      | 322/1000 [00:40&lt;01:31,  7.42it/s] 32%|███▏      | 323/1000 [00:40&lt;01:35,  7.10it/s] 32%|███▏      | 324/1000 [00:40&lt;01:37,  6.91it/s] 32%|███▎      | 325/1000 [00:40&lt;01:38,  6.88it/s] 33%|███▎      | 326/1000 [00:41&lt;01:44,  6.48it/s] 33%|███▎      | 327/1000 [00:41&lt;01:49,  6.15it/s] 33%|███▎      | 328/1000 [00:41&lt;02:03,  5.43it/s] 33%|███▎      | 329/1000 [00:41&lt;02:00,  5.58it/s] 33%|███▎      | 330/1000 [00:41&lt;01:56,  5.75it/s] 33%|███▎      | 331/1000 [00:41&lt;01:49,  6.13it/s] 33%|███▎      | 332/1000 [00:42&lt;01:48,  6.16it/s] 33%|███▎      | 333/1000 [00:42&lt;01:46,  6.24it/s] 33%|███▎      | 334/1000 [00:42&lt;01:48,  6.13it/s] 34%|███▎      | 335/1000 [00:42&lt;02:16,  4.86it/s] 34%|███▎      | 336/1000 [00:42&lt;02:18,  4.81it/s] 34%|███▎      | 337/1000 [00:43&lt;02:13,  4.96it/s] 34%|███▍      | 338/1000 [00:43&lt;02:15,  4.88it/s] 34%|███▍      | 339/1000 [00:43&lt;02:12,  4.98it/s] 34%|███▍      | 340/1000 [00:43&lt;02:03,  5.33it/s] 34%|███▍      | 341/1000 [00:43&lt;01:59,  5.50it/s] 34%|███▍      | 342/1000 [00:44&lt;01:56,  5.65it/s] 34%|███▍      | 343/1000 [00:44&lt;01:53,  5.80it/s] 34%|███▍      | 344/1000 [00:44&lt;01:51,  5.88it/s] 34%|███▍      | 345/1000 [00:44&lt;01:51,  5.90it/s] 35%|███▍      | 346/1000 [00:44&lt;01:51,  5.88it/s] 35%|███▍      | 347/1000 [00:44&lt;01:52,  5.80it/s] 35%|███▍      | 348/1000 [00:45&lt;01:55,  5.63it/s] 35%|███▍      | 349/1000 [00:45&lt;01:57,  5.52it/s] 35%|███▌      | 350/1000 [00:45&lt;01:53,  5.72it/s] 35%|███▌      | 351/1000 [00:45&lt;01:55,  5.61it/s] 35%|███▌      | 352/1000 [00:45&lt;01:55,  5.62it/s] 35%|███▌      | 353/1000 [00:45&lt;01:59,  5.44it/s] 35%|███▌      | 354/1000 [00:46&lt;02:02,  5.27it/s] 36%|███▌      | 355/1000 [00:46&lt;02:33,  4.21it/s] 36%|███▌      | 356/1000 [00:46&lt;02:20,  4.58it/s] 36%|███▌      | 357/1000 [00:46&lt;02:08,  5.01it/s] 36%|███▌      | 358/1000 [00:47&lt;02:02,  5.25it/s] 36%|███▌      | 359/1000 [00:47&lt;01:55,  5.56it/s] 36%|███▌      | 360/1000 [00:47&lt;01:51,  5.74it/s] 36%|███▌      | 361/1000 [00:47&lt;01:50,  5.77it/s] 36%|███▌      | 362/1000 [00:47&lt;01:47,  5.94it/s] 36%|███▋      | 363/1000 [00:47&lt;01:47,  5.92it/s] 36%|███▋      | 364/1000 [00:48&lt;01:51,  5.71it/s] 36%|███▋      | 365/1000 [00:48&lt;01:53,  5.59it/s] 37%|███▋      | 366/1000 [00:48&lt;01:57,  5.42it/s] 37%|███▋      | 367/1000 [00:48&lt;01:59,  5.28it/s] 37%|███▋      | 368/1000 [00:48&lt;02:03,  5.13it/s] 37%|███▋      | 369/1000 [00:48&lt;01:56,  5.42it/s] 37%|███▋      | 370/1000 [00:49&lt;01:52,  5.58it/s] 37%|███▋      | 371/1000 [00:49&lt;01:47,  5.86it/s] 37%|███▋      | 372/1000 [00:49&lt;01:54,  5.51it/s] 37%|███▋      | 373/1000 [00:49&lt;01:51,  5.65it/s] 37%|███▋      | 374/1000 [00:49&lt;01:56,  5.36it/s] 38%|███▊      | 375/1000 [00:50&lt;02:07,  4.92it/s] 38%|███▊      | 376/1000 [00:50&lt;02:06,  4.94it/s] 38%|███▊      | 377/1000 [00:50&lt;02:04,  5.01it/s] 38%|███▊      | 378/1000 [00:50&lt;01:56,  5.35it/s] 38%|███▊      | 379/1000 [00:50&lt;01:56,  5.33it/s] 38%|███▊      | 380/1000 [00:51&lt;01:58,  5.25it/s] 38%|███▊      | 381/1000 [00:51&lt;01:56,  5.31it/s] 38%|███▊      | 382/1000 [00:51&lt;01:51,  5.53it/s] 38%|███▊      | 383/1000 [00:51&lt;01:49,  5.64it/s] 38%|███▊      | 384/1000 [00:51&lt;01:52,  5.49it/s] 38%|███▊      | 385/1000 [00:51&lt;01:51,  5.53it/s] 39%|███▊      | 386/1000 [00:52&lt;01:50,  5.56it/s] 39%|███▊      | 387/1000 [00:52&lt;01:48,  5.63it/s] 39%|███▉      | 388/1000 [00:52&lt;02:03,  4.96it/s] 39%|███▉      | 389/1000 [00:52&lt;01:59,  5.13it/s] 39%|███▉      | 390/1000 [00:52&lt;02:07,  4.79it/s] 39%|███▉      | 391/1000 [00:53&lt;02:11,  4.62it/s] 39%|███▉      | 392/1000 [00:53&lt;02:17,  4.41it/s] 39%|███▉      | 393/1000 [00:53&lt;02:14,  4.52it/s] 39%|███▉      | 394/1000 [00:53&lt;02:03,  4.91it/s] 40%|███▉      | 395/1000 [00:54&lt;01:58,  5.13it/s] 40%|███▉      | 396/1000 [00:54&lt;01:54,  5.25it/s] 40%|███▉      | 397/1000 [00:54&lt;01:50,  5.48it/s] 40%|███▉      | 398/1000 [00:54&lt;01:47,  5.57it/s] 40%|███▉      | 399/1000 [00:54&lt;01:53,  5.30it/s] 40%|████      | 400/1000 [00:55&lt;02:10,  4.59it/s] 40%|████      | 401/1000 [00:55&lt;02:12,  4.51it/s] 40%|████      | 402/1000 [00:55&lt;02:17,  4.34it/s] 40%|████      | 403/1000 [00:55&lt;02:21,  4.22it/s] 40%|████      | 404/1000 [00:56&lt;02:28,  4.01it/s] 40%|████      | 405/1000 [00:56&lt;02:19,  4.27it/s] 41%|████      | 406/1000 [00:56&lt;02:09,  4.59it/s] 41%|████      | 407/1000 [00:56&lt;02:01,  4.89it/s] 41%|████      | 408/1000 [00:56&lt;01:55,  5.12it/s] 41%|████      | 409/1000 [00:56&lt;01:50,  5.34it/s] 41%|████      | 410/1000 [00:57&lt;01:47,  5.47it/s] 41%|████      | 411/1000 [00:57&lt;01:42,  5.74it/s] 41%|████      | 412/1000 [00:57&lt;01:37,  6.05it/s] 41%|████▏     | 413/1000 [00:57&lt;01:36,  6.08it/s] 41%|████▏     | 414/1000 [00:57&lt;01:42,  5.73it/s] 42%|████▏     | 415/1000 [00:57&lt;01:50,  5.32it/s] 42%|████▏     | 416/1000 [00:58&lt;01:51,  5.25it/s] 42%|████▏     | 417/1000 [00:58&lt;02:13,  4.36it/s] 42%|████▏     | 418/1000 [00:58&lt;02:13,  4.35it/s] 42%|████▏     | 419/1000 [00:58&lt;02:06,  4.58it/s] 42%|████▏     | 420/1000 [00:59&lt;01:59,  4.85it/s] 42%|████▏     | 421/1000 [00:59&lt;01:58,  4.90it/s] 42%|████▏     | 422/1000 [00:59&lt;01:57,  4.91it/s] 42%|████▏     | 423/1000 [00:59&lt;01:57,  4.93it/s] 42%|████▏     | 424/1000 [00:59&lt;01:51,  5.18it/s] 42%|████▎     | 425/1000 [01:00&lt;01:53,  5.06it/s] 43%|████▎     | 426/1000 [01:00&lt;01:53,  5.05it/s] 43%|████▎     | 427/1000 [01:00&lt;01:51,  5.13it/s] 43%|████▎     | 428/1000 [01:00&lt;01:55,  4.94it/s] 43%|████▎     | 429/1000 [01:00&lt;01:53,  5.01it/s] 43%|████▎     | 430/1000 [01:01&lt;01:51,  5.09it/s] 43%|████▎     | 431/1000 [01:01&lt;01:48,  5.27it/s] 43%|████▎     | 432/1000 [01:01&lt;01:44,  5.46it/s] 43%|████▎     | 433/1000 [01:01&lt;01:39,  5.71it/s] 43%|████▎     | 434/1000 [01:01&lt;01:36,  5.86it/s] 44%|████▎     | 435/1000 [01:01&lt;01:33,  6.02it/s] 44%|████▎     | 436/1000 [01:02&lt;01:30,  6.21it/s] 44%|████▎     | 437/1000 [01:02&lt;01:30,  6.23it/s] 44%|████▍     | 438/1000 [01:02&lt;01:31,  6.13it/s] 44%|████▍     | 439/1000 [01:02&lt;01:32,  6.10it/s] 44%|████▍     | 440/1000 [01:02&lt;01:36,  5.80it/s] 44%|████▍     | 441/1000 [01:02&lt;01:49,  5.09it/s] 44%|████▍     | 442/1000 [01:03&lt;01:53,  4.90it/s] 44%|████▍     | 443/1000 [01:03&lt;01:56,  4.77it/s] 44%|████▍     | 444/1000 [01:03&lt;01:48,  5.13it/s] 44%|████▍     | 445/1000 [01:03&lt;01:46,  5.22it/s] 45%|████▍     | 446/1000 [01:04&lt;01:57,  4.73it/s] 45%|████▍     | 447/1000 [01:04&lt;02:04,  4.44it/s] 45%|████▍     | 448/1000 [01:04&lt;02:01,  4.56it/s] 45%|████▍     | 449/1000 [01:04&lt;02:00,  4.57it/s] 45%|████▌     | 450/1000 [01:04&lt;02:00,  4.56it/s] 45%|████▌     | 451/1000 [01:05&lt;02:07,  4.30it/s] 45%|████▌     | 452/1000 [01:05&lt;02:05,  4.36it/s] 45%|████▌     | 453/1000 [01:05&lt;02:04,  4.40it/s] 45%|████▌     | 454/1000 [01:05&lt;02:03,  4.44it/s] 46%|████▌     | 455/1000 [01:06&lt;02:11,  4.16it/s] 46%|████▌     | 456/1000 [01:06&lt;02:32,  3.56it/s] 46%|████▌     | 457/1000 [01:06&lt;02:30,  3.61it/s] 46%|████▌     | 458/1000 [01:06&lt;02:19,  3.90it/s] 46%|████▌     | 459/1000 [01:07&lt;02:16,  3.95it/s] 46%|████▌     | 460/1000 [01:07&lt;02:13,  4.05it/s] 46%|████▌     | 461/1000 [01:07&lt;02:11,  4.11it/s] 46%|████▌     | 462/1000 [01:07&lt;02:06,  4.26it/s] 46%|████▋     | 463/1000 [01:08&lt;02:00,  4.47it/s] 46%|████▋     | 464/1000 [01:08&lt;01:56,  4.62it/s] 46%|████▋     | 465/1000 [01:08&lt;01:49,  4.90it/s] 47%|████▋     | 466/1000 [01:08&lt;01:45,  5.07it/s] 47%|████▋     | 467/1000 [01:08&lt;01:44,  5.12it/s] 47%|████▋     | 468/1000 [01:09&lt;01:45,  5.07it/s] 47%|████▋     | 469/1000 [01:09&lt;01:45,  5.05it/s] 47%|████▋     | 470/1000 [01:09&lt;01:46,  4.99it/s] 47%|████▋     | 471/1000 [01:09&lt;01:43,  5.11it/s] 47%|████▋     | 472/1000 [01:09&lt;01:41,  5.19it/s] 47%|████▋     | 473/1000 [01:10&lt;01:46,  4.93it/s] 47%|████▋     | 474/1000 [01:10&lt;01:46,  4.93it/s] 48%|████▊     | 475/1000 [01:10&lt;01:47,  4.88it/s] 48%|████▊     | 476/1000 [01:10&lt;01:51,  4.69it/s] 48%|████▊     | 477/1000 [01:10&lt;01:55,  4.54it/s] 48%|████▊     | 478/1000 [01:11&lt;02:06,  4.12it/s] 48%|████▊     | 479/1000 [01:11&lt;02:12,  3.92it/s] 48%|████▊     | 480/1000 [01:11&lt;02:05,  4.15it/s] 48%|████▊     | 481/1000 [01:11&lt;02:02,  4.22it/s] 48%|████▊     | 482/1000 [01:12&lt;01:57,  4.42it/s] 48%|████▊     | 483/1000 [01:12&lt;01:51,  4.65it/s] 48%|████▊     | 484/1000 [01:12&lt;01:58,  4.36it/s] 48%|████▊     | 485/1000 [01:12&lt;02:13,  3.85it/s] 49%|████▊     | 486/1000 [01:13&lt;02:03,  4.15it/s] 49%|████▊     | 487/1000 [01:13&lt;01:56,  4.40it/s] 49%|████▉     | 488/1000 [01:13&lt;01:56,  4.41it/s] 49%|████▉     | 489/1000 [01:13&lt;01:50,  4.61it/s] 49%|████▉     | 490/1000 [01:13&lt;01:54,  4.47it/s] 49%|████▉     | 491/1000 [01:14&lt;02:01,  4.18it/s] 49%|████▉     | 492/1000 [01:14&lt;01:58,  4.30it/s] 49%|████▉     | 493/1000 [01:14&lt;01:51,  4.55it/s] 49%|████▉     | 494/1000 [01:14&lt;01:49,  4.63it/s] 50%|████▉     | 495/1000 [01:15&lt;01:49,  4.62it/s] 50%|████▉     | 496/1000 [01:15&lt;01:47,  4.70it/s] 50%|████▉     | 497/1000 [01:15&lt;01:42,  4.89it/s] 50%|████▉     | 498/1000 [01:15&lt;01:41,  4.94it/s] 50%|████▉     | 499/1000 [01:15&lt;01:46,  4.72it/s] 50%|█████     | 500/1000 [01:16&lt;02:02,  4.07it/s] 50%|█████     | 501/1000 [01:16&lt;02:20,  3.54it/s] 50%|█████     | 502/1000 [01:16&lt;02:12,  3.76it/s] 50%|█████     | 503/1000 [01:17&lt;02:15,  3.66it/s] 50%|█████     | 504/1000 [01:17&lt;02:19,  3.56it/s] 50%|█████     | 505/1000 [01:17&lt;02:18,  3.59it/s] 51%|█████     | 506/1000 [01:18&lt;02:25,  3.39it/s] 51%|█████     | 507/1000 [01:18&lt;02:16,  3.60it/s] 51%|█████     | 508/1000 [01:18&lt;02:11,  3.74it/s] 51%|█████     | 509/1000 [01:19&lt;02:46,  2.95it/s] 51%|█████     | 510/1000 [01:19&lt;03:04,  2.66it/s] 51%|█████     | 511/1000 [01:19&lt;03:07,  2.61it/s] 51%|█████     | 512/1000 [01:20&lt;03:01,  2.69it/s] 51%|█████▏    | 513/1000 [01:20&lt;02:57,  2.75it/s] 51%|█████▏    | 514/1000 [01:20&lt;02:48,  2.89it/s] 52%|█████▏    | 515/1000 [01:21&lt;02:56,  2.75it/s] 52%|█████▏    | 516/1000 [01:21&lt;03:04,  2.62it/s] 52%|█████▏    | 517/1000 [01:22&lt;02:54,  2.76it/s] 52%|█████▏    | 518/1000 [01:22&lt;02:35,  3.11it/s] 52%|█████▏    | 519/1000 [01:22&lt;02:14,  3.58it/s] 52%|█████▏    | 520/1000 [01:22&lt;02:11,  3.64it/s] 52%|█████▏    | 521/1000 [01:22&lt;01:59,  4.02it/s] 52%|█████▏    | 522/1000 [01:23&lt;01:58,  4.05it/s] 52%|█████▏    | 523/1000 [01:23&lt;01:58,  4.04it/s] 52%|█████▏    | 524/1000 [01:23&lt;02:00,  3.96it/s] 52%|█████▎    | 525/1000 [01:23&lt;01:52,  4.21it/s] 53%|█████▎    | 526/1000 [01:24&lt;01:53,  4.18it/s] 53%|█████▎    | 527/1000 [01:24&lt;01:50,  4.29it/s] 53%|█████▎    | 528/1000 [01:24&lt;01:44,  4.50it/s] 53%|█████▎    | 529/1000 [01:24&lt;01:45,  4.47it/s] 53%|█████▎    | 530/1000 [01:24&lt;01:41,  4.61it/s] 53%|█████▎    | 531/1000 [01:25&lt;01:45,  4.46it/s] 53%|█████▎    | 532/1000 [01:25&lt;01:48,  4.31it/s] 53%|█████▎    | 533/1000 [01:25&lt;01:47,  4.36it/s] 53%|█████▎    | 534/1000 [01:25&lt;01:51,  4.18it/s] 54%|█████▎    | 535/1000 [01:26&lt;02:01,  3.83it/s] 54%|█████▎    | 536/1000 [01:26&lt;01:57,  3.94it/s] 54%|█████▎    | 537/1000 [01:26&lt;01:52,  4.11it/s] 54%|█████▍    | 538/1000 [01:26&lt;01:47,  4.30it/s] 54%|█████▍    | 539/1000 [01:27&lt;01:40,  4.56it/s] 54%|█████▍    | 540/1000 [01:27&lt;01:38,  4.66it/s] 54%|█████▍    | 541/1000 [01:27&lt;01:34,  4.87it/s] 54%|█████▍    | 542/1000 [01:27&lt;01:29,  5.10it/s] 54%|█████▍    | 543/1000 [01:27&lt;01:28,  5.16it/s] 54%|█████▍    | 544/1000 [01:27&lt;01:26,  5.28it/s] 55%|█████▍    | 545/1000 [01:28&lt;01:26,  5.28it/s] 55%|█████▍    | 546/1000 [01:28&lt;01:24,  5.37it/s] 55%|█████▍    | 547/1000 [01:28&lt;01:22,  5.46it/s] 55%|█████▍    | 548/1000 [01:28&lt;01:27,  5.16it/s] 55%|█████▍    | 549/1000 [01:28&lt;01:24,  5.36it/s] 55%|█████▌    | 550/1000 [01:29&lt;01:20,  5.59it/s] 55%|█████▌    | 551/1000 [01:29&lt;01:16,  5.87it/s] 55%|█████▌    | 552/1000 [01:29&lt;01:13,  6.06it/s] 55%|█████▌    | 553/1000 [01:29&lt;01:12,  6.17it/s] 55%|█████▌    | 554/1000 [01:29&lt;01:15,  5.93it/s] 56%|█████▌    | 555/1000 [01:29&lt;01:22,  5.39it/s] 56%|█████▌    | 556/1000 [01:30&lt;01:25,  5.19it/s] 56%|█████▌    | 557/1000 [01:30&lt;01:25,  5.18it/s] 56%|█████▌    | 558/1000 [01:30&lt;01:25,  5.18it/s] 56%|█████▌    | 559/1000 [01:31&lt;02:05,  3.50it/s] 56%|█████▌    | 560/1000 [01:31&lt;02:13,  3.31it/s] 56%|█████▌    | 561/1000 [01:31&lt;02:06,  3.46it/s] 56%|█████▌    | 562/1000 [01:31&lt;01:52,  3.88it/s] 56%|█████▋    | 563/1000 [01:32&lt;01:46,  4.10it/s] 56%|█████▋    | 564/1000 [01:32&lt;01:42,  4.25it/s] 56%|█████▋    | 565/1000 [01:32&lt;01:37,  4.47it/s] 57%|█████▋    | 566/1000 [01:32&lt;01:31,  4.76it/s] 57%|█████▋    | 567/1000 [01:32&lt;01:35,  4.51it/s] 57%|█████▋    | 568/1000 [01:33&lt;01:37,  4.44it/s] 57%|█████▋    | 569/1000 [01:33&lt;01:31,  4.70it/s] 57%|█████▋    | 570/1000 [01:33&lt;01:29,  4.83it/s] 57%|█████▋    | 571/1000 [01:33&lt;01:31,  4.68it/s] 57%|█████▋    | 572/1000 [01:33&lt;01:34,  4.53it/s] 57%|█████▋    | 573/1000 [01:34&lt;01:31,  4.65it/s] 57%|█████▋    | 574/1000 [01:34&lt;01:26,  4.95it/s] 57%|█████▊    | 575/1000 [01:34&lt;01:22,  5.14it/s] 58%|█████▊    | 576/1000 [01:34&lt;01:23,  5.10it/s] 58%|█████▊    | 577/1000 [01:34&lt;01:24,  5.01it/s] 58%|█████▊    | 578/1000 [01:35&lt;01:21,  5.16it/s] 58%|█████▊    | 579/1000 [01:35&lt;01:19,  5.28it/s] 58%|█████▊    | 580/1000 [01:35&lt;01:17,  5.43it/s] 58%|█████▊    | 581/1000 [01:35&lt;01:16,  5.46it/s] 58%|█████▊    | 582/1000 [01:35&lt;01:22,  5.09it/s] 58%|█████▊    | 583/1000 [01:36&lt;01:33,  4.45it/s] 58%|█████▊    | 584/1000 [01:36&lt;01:30,  4.57it/s] 58%|█████▊    | 585/1000 [01:36&lt;01:31,  4.53it/s] 59%|█████▊    | 586/1000 [01:36&lt;01:31,  4.55it/s] 59%|█████▊    | 587/1000 [01:36&lt;01:26,  4.75it/s] 59%|█████▉    | 588/1000 [01:37&lt;01:23,  4.91it/s] 59%|█████▉    | 589/1000 [01:37&lt;01:19,  5.17it/s] 59%|█████▉    | 590/1000 [01:37&lt;01:19,  5.18it/s] 59%|█████▉    | 591/1000 [01:37&lt;01:29,  4.60it/s] 59%|█████▉    | 592/1000 [01:38&lt;01:32,  4.42it/s] 59%|█████▉    | 593/1000 [01:38&lt;01:37,  4.17it/s] 59%|█████▉    | 594/1000 [01:38&lt;01:51,  3.64it/s] 60%|█████▉    | 595/1000 [01:38&lt;01:46,  3.82it/s] 60%|█████▉    | 596/1000 [01:39&lt;01:39,  4.06it/s] 60%|█████▉    | 597/1000 [01:39&lt;01:31,  4.39it/s] 60%|█████▉    | 598/1000 [01:39&lt;01:28,  4.56it/s] 60%|█████▉    | 599/1000 [01:39&lt;01:24,  4.77it/s] 60%|██████    | 600/1000 [01:39&lt;01:27,  4.58it/s] 60%|██████    | 601/1000 [01:40&lt;01:26,  4.62it/s] 60%|██████    | 602/1000 [01:40&lt;01:20,  4.92it/s] 60%|██████    | 603/1000 [01:40&lt;01:23,  4.77it/s] 60%|██████    | 604/1000 [01:40&lt;01:28,  4.48it/s] 60%|██████    | 605/1000 [01:41&lt;01:42,  3.85it/s] 61%|██████    | 606/1000 [01:41&lt;01:39,  3.96it/s] 61%|██████    | 607/1000 [01:41&lt;01:31,  4.28it/s] 61%|██████    | 608/1000 [01:41&lt;01:26,  4.53it/s] 61%|██████    | 609/1000 [01:41&lt;01:28,  4.43it/s] 61%|██████    | 610/1000 [01:42&lt;01:31,  4.28it/s] 61%|██████    | 611/1000 [01:42&lt;01:29,  4.37it/s] 61%|██████    | 612/1000 [01:42&lt;01:40,  3.85it/s] 61%|██████▏   | 613/1000 [01:43&lt;01:44,  3.71it/s] 61%|██████▏   | 614/1000 [01:43&lt;01:40,  3.83it/s] 62%|██████▏   | 615/1000 [01:43&lt;01:40,  3.84it/s] 62%|██████▏   | 616/1000 [01:43&lt;01:36,  3.97it/s] 62%|██████▏   | 617/1000 [01:44&lt;01:29,  4.27it/s] 62%|██████▏   | 618/1000 [01:44&lt;01:24,  4.52it/s] 62%|██████▏   | 619/1000 [01:44&lt;01:20,  4.74it/s] 62%|██████▏   | 620/1000 [01:44&lt;01:15,  5.05it/s] 62%|██████▏   | 621/1000 [01:44&lt;01:18,  4.84it/s] 62%|██████▏   | 622/1000 [01:45&lt;01:23,  4.53it/s] 62%|██████▏   | 623/1000 [01:45&lt;01:22,  4.54it/s] 62%|██████▏   | 624/1000 [01:45&lt;01:15,  4.96it/s] 62%|██████▎   | 625/1000 [01:45&lt;01:06,  5.65it/s] 63%|██████▎   | 626/1000 [01:45&lt;00:59,  6.30it/s] 63%|██████▎   | 627/1000 [01:45&lt;00:54,  6.80it/s] 63%|██████▎   | 628/1000 [01:45&lt;00:51,  7.20it/s] 63%|██████▎   | 629/1000 [01:46&lt;00:55,  6.69it/s] 63%|██████▎   | 630/1000 [01:46&lt;01:05,  5.65it/s] 63%|██████▎   | 631/1000 [01:46&lt;00:58,  6.26it/s] 63%|██████▎   | 632/1000 [01:46&lt;00:57,  6.40it/s] 63%|██████▎   | 633/1000 [01:46&lt;00:56,  6.52it/s] 63%|██████▎   | 634/1000 [01:46&lt;00:56,  6.49it/s] 64%|██████▎   | 635/1000 [01:47&lt;00:59,  6.09it/s] 64%|██████▎   | 636/1000 [01:47&lt;01:02,  5.83it/s] 64%|██████▎   | 637/1000 [01:47&lt;00:59,  6.09it/s] 64%|██████▍   | 638/1000 [01:47&lt;01:05,  5.49it/s] 64%|██████▍   | 639/1000 [01:47&lt;01:06,  5.44it/s] 64%|██████▍   | 640/1000 [01:48&lt;01:10,  5.13it/s] 64%|██████▍   | 641/1000 [01:48&lt;01:11,  5.06it/s] 64%|██████▍   | 642/1000 [01:48&lt;01:08,  5.24it/s] 64%|██████▍   | 643/1000 [01:48&lt;01:14,  4.82it/s] 64%|██████▍   | 644/1000 [01:49&lt;01:36,  3.69it/s] 64%|██████▍   | 645/1000 [01:49&lt;01:28,  4.03it/s] 65%|██████▍   | 646/1000 [01:49&lt;01:21,  4.33it/s] 65%|██████▍   | 647/1000 [01:49&lt;01:15,  4.69it/s] 65%|██████▍   | 648/1000 [01:49&lt;01:11,  4.92it/s] 65%|██████▍   | 649/1000 [01:50&lt;01:11,  4.94it/s] 65%|██████▌   | 650/1000 [01:50&lt;01:10,  4.95it/s] 65%|██████▌   | 651/1000 [01:50&lt;01:11,  4.86it/s] 65%|██████▌   | 652/1000 [01:50&lt;01:11,  4.84it/s] 65%|██████▌   | 653/1000 [01:50&lt;01:14,  4.69it/s] 65%|██████▌   | 654/1000 [01:51&lt;01:16,  4.54it/s] 66%|██████▌   | 655/1000 [01:51&lt;01:11,  4.79it/s] 66%|██████▌   | 656/1000 [01:51&lt;01:11,  4.79it/s] 66%|██████▌   | 657/1000 [01:51&lt;01:09,  4.92it/s] 66%|██████▌   | 658/1000 [01:51&lt;01:08,  4.96it/s] 66%|██████▌   | 659/1000 [01:52&lt;01:08,  4.99it/s] 66%|██████▌   | 660/1000 [01:52&lt;01:07,  5.04it/s] 66%|██████▌   | 661/1000 [01:52&lt;01:03,  5.33it/s] 66%|██████▌   | 662/1000 [01:52&lt;01:02,  5.38it/s] 66%|██████▋   | 663/1000 [01:52&lt;01:02,  5.36it/s] 66%|██████▋   | 664/1000 [01:52&lt;01:02,  5.39it/s] 66%|██████▋   | 665/1000 [01:53&lt;01:02,  5.37it/s] 67%|██████▋   | 666/1000 [01:53&lt;01:01,  5.42it/s] 67%|██████▋   | 667/1000 [01:53&lt;00:59,  5.55it/s] 67%|██████▋   | 668/1000 [01:53&lt;01:00,  5.53it/s] 67%|██████▋   | 669/1000 [01:53&lt;01:01,  5.37it/s] 67%|██████▋   | 670/1000 [01:54&lt;01:02,  5.32it/s] 67%|██████▋   | 671/1000 [01:54&lt;01:03,  5.17it/s] 67%|██████▋   | 672/1000 [01:54&lt;01:05,  5.04it/s] 67%|██████▋   | 673/1000 [01:54&lt;01:07,  4.85it/s] 67%|██████▋   | 674/1000 [01:54&lt;01:08,  4.78it/s] 68%|██████▊   | 675/1000 [01:55&lt;01:11,  4.52it/s] 68%|██████▊   | 676/1000 [01:55&lt;01:05,  4.96it/s] 68%|██████▊   | 677/1000 [01:55&lt;01:00,  5.38it/s] 68%|██████▊   | 678/1000 [01:55&lt;00:56,  5.74it/s] 68%|██████▊   | 679/1000 [01:55&lt;00:55,  5.82it/s] 68%|██████▊   | 680/1000 [01:55&lt;00:52,  6.10it/s] 68%|██████▊   | 681/1000 [01:56&lt;00:53,  5.91it/s] 68%|██████▊   | 682/1000 [01:56&lt;00:51,  6.14it/s] 68%|██████▊   | 683/1000 [01:56&lt;00:50,  6.24it/s] 68%|██████▊   | 684/1000 [01:56&lt;00:46,  6.76it/s] 68%|██████▊   | 685/1000 [01:56&lt;00:43,  7.18it/s] 69%|██████▊   | 686/1000 [01:56&lt;00:43,  7.16it/s] 69%|██████▊   | 687/1000 [01:56&lt;00:42,  7.38it/s] 69%|██████▉   | 688/1000 [01:57&lt;00:42,  7.32it/s] 69%|██████▉   | 689/1000 [01:57&lt;00:42,  7.31it/s] 69%|██████▉   | 690/1000 [01:57&lt;00:40,  7.60it/s] 69%|██████▉   | 691/1000 [01:57&lt;00:39,  7.87it/s] 69%|██████▉   | 692/1000 [01:57&lt;00:38,  7.98it/s] 69%|██████▉   | 693/1000 [01:57&lt;00:38,  8.00it/s] 69%|██████▉   | 694/1000 [01:57&lt;00:38,  8.03it/s] 70%|██████▉   | 695/1000 [01:57&lt;00:38,  7.90it/s] 70%|██████▉   | 696/1000 [01:58&lt;00:39,  7.65it/s] 70%|██████▉   | 697/1000 [01:58&lt;00:39,  7.73it/s] 70%|██████▉   | 698/1000 [01:58&lt;00:37,  8.06it/s] 70%|██████▉   | 699/1000 [01:58&lt;00:36,  8.16it/s] 70%|███████   | 700/1000 [01:58&lt;00:35,  8.41it/s] 70%|███████   | 701/1000 [01:58&lt;00:35,  8.45it/s] 70%|███████   | 702/1000 [01:58&lt;00:35,  8.48it/s] 70%|███████   | 703/1000 [01:58&lt;00:34,  8.53it/s] 70%|███████   | 704/1000 [01:59&lt;00:34,  8.49it/s] 70%|███████   | 705/1000 [01:59&lt;00:35,  8.21it/s] 71%|███████   | 706/1000 [01:59&lt;00:35,  8.34it/s] 71%|███████   | 707/1000 [01:59&lt;00:34,  8.42it/s] 71%|███████   | 708/1000 [01:59&lt;00:34,  8.58it/s] 71%|███████   | 709/1000 [01:59&lt;00:33,  8.62it/s] 71%|███████   | 710/1000 [01:59&lt;00:33,  8.63it/s] 71%|███████   | 711/1000 [01:59&lt;00:33,  8.66it/s] 71%|███████   | 712/1000 [01:59&lt;00:32,  8.74it/s] 71%|███████▏  | 713/1000 [02:00&lt;00:33,  8.67it/s] 71%|███████▏  | 714/1000 [02:00&lt;00:33,  8.52it/s] 72%|███████▏  | 715/1000 [02:00&lt;00:32,  8.64it/s] 72%|███████▏  | 716/1000 [02:00&lt;00:33,  8.60it/s] 72%|███████▏  | 717/1000 [02:00&lt;00:32,  8.67it/s] 72%|███████▏  | 718/1000 [02:00&lt;00:32,  8.71it/s] 72%|███████▏  | 719/1000 [02:00&lt;00:32,  8.72it/s] 72%|███████▏  | 720/1000 [02:00&lt;00:32,  8.72it/s] 72%|███████▏  | 721/1000 [02:01&lt;00:32,  8.49it/s] 72%|███████▏  | 722/1000 [02:01&lt;00:33,  8.34it/s] 72%|███████▏  | 723/1000 [02:01&lt;00:32,  8.42it/s] 72%|███████▏  | 724/1000 [02:01&lt;00:32,  8.47it/s] 72%|███████▎  | 725/1000 [02:01&lt;00:31,  8.61it/s] 73%|███████▎  | 726/1000 [02:01&lt;00:31,  8.62it/s] 73%|███████▎  | 727/1000 [02:01&lt;00:31,  8.68it/s] 73%|███████▎  | 728/1000 [02:01&lt;00:31,  8.70it/s] 73%|███████▎  | 729/1000 [02:01&lt;00:31,  8.74it/s] 73%|███████▎  | 730/1000 [02:02&lt;00:30,  8.76it/s] 73%|███████▎  | 731/1000 [02:02&lt;00:30,  8.77it/s] 73%|███████▎  | 732/1000 [02:02&lt;00:30,  8.75it/s] 73%|███████▎  | 733/1000 [02:02&lt;00:30,  8.79it/s] 73%|███████▎  | 734/1000 [02:02&lt;00:29,  8.87it/s] 74%|███████▎  | 735/1000 [02:02&lt;00:29,  8.85it/s] 74%|███████▎  | 736/1000 [02:02&lt;00:31,  8.46it/s] 74%|███████▎  | 737/1000 [02:02&lt;00:31,  8.42it/s] 74%|███████▍  | 738/1000 [02:02&lt;00:30,  8.53it/s] 74%|███████▍  | 739/1000 [02:03&lt;00:30,  8.60it/s] 74%|███████▍  | 740/1000 [02:03&lt;00:30,  8.64it/s] 74%|███████▍  | 741/1000 [02:03&lt;00:29,  8.74it/s] 74%|███████▍  | 742/1000 [02:03&lt;00:29,  8.71it/s] 74%|███████▍  | 743/1000 [02:03&lt;00:30,  8.37it/s] 74%|███████▍  | 744/1000 [02:03&lt;00:32,  7.86it/s] 74%|███████▍  | 745/1000 [02:03&lt;00:32,  7.91it/s] 75%|███████▍  | 746/1000 [02:03&lt;00:31,  8.02it/s] 75%|███████▍  | 747/1000 [02:04&lt;00:30,  8.24it/s] 75%|███████▍  | 748/1000 [02:04&lt;00:31,  8.01it/s] 75%|███████▍  | 749/1000 [02:04&lt;00:31,  7.96it/s] 75%|███████▌  | 750/1000 [02:04&lt;00:31,  8.05it/s] 75%|███████▌  | 751/1000 [02:04&lt;00:31,  7.80it/s] 75%|███████▌  | 752/1000 [02:04&lt;00:33,  7.48it/s] 75%|███████▌  | 753/1000 [02:04&lt;00:33,  7.45it/s] 75%|███████▌  | 754/1000 [02:05&lt;00:32,  7.47it/s] 76%|███████▌  | 755/1000 [02:05&lt;00:33,  7.42it/s] 76%|███████▌  | 756/1000 [02:05&lt;00:34,  7.15it/s] 76%|███████▌  | 757/1000 [02:05&lt;00:36,  6.65it/s] 76%|███████▌  | 758/1000 [02:05&lt;00:38,  6.27it/s] 76%|███████▌  | 759/1000 [02:05&lt;00:37,  6.44it/s] 76%|███████▌  | 760/1000 [02:05&lt;00:38,  6.22it/s] 76%|███████▌  | 761/1000 [02:06&lt;00:39,  6.11it/s] 76%|███████▌  | 762/1000 [02:06&lt;00:38,  6.17it/s] 76%|███████▋  | 763/1000 [02:06&lt;00:38,  6.11it/s] 76%|███████▋  | 764/1000 [02:06&lt;00:38,  6.12it/s] 76%|███████▋  | 765/1000 [02:06&lt;00:36,  6.45it/s] 77%|███████▋  | 766/1000 [02:06&lt;00:35,  6.61it/s] 77%|███████▋  | 767/1000 [02:07&lt;00:33,  6.93it/s] 77%|███████▋  | 768/1000 [02:07&lt;00:32,  7.06it/s] 77%|███████▋  | 769/1000 [02:07&lt;00:32,  7.07it/s] 77%|███████▋  | 770/1000 [02:07&lt;00:31,  7.40it/s] 77%|███████▋  | 771/1000 [02:07&lt;00:29,  7.81it/s] 77%|███████▋  | 772/1000 [02:07&lt;00:28,  8.06it/s] 77%|███████▋  | 773/1000 [02:07&lt;00:27,  8.27it/s] 77%|███████▋  | 774/1000 [02:07&lt;00:26,  8.47it/s] 78%|███████▊  | 775/1000 [02:08&lt;00:26,  8.57it/s] 78%|███████▊  | 776/1000 [02:08&lt;00:26,  8.58it/s] 78%|███████▊  | 777/1000 [02:08&lt;00:26,  8.51it/s] 78%|███████▊  | 778/1000 [02:08&lt;00:25,  8.66it/s] 78%|███████▊  | 779/1000 [02:08&lt;00:25,  8.70it/s] 78%|███████▊  | 780/1000 [02:08&lt;00:25,  8.65it/s] 78%|███████▊  | 781/1000 [02:08&lt;00:25,  8.65it/s] 78%|███████▊  | 782/1000 [02:08&lt;00:25,  8.70it/s] 78%|███████▊  | 783/1000 [02:08&lt;00:25,  8.67it/s] 78%|███████▊  | 784/1000 [02:09&lt;00:24,  8.76it/s] 78%|███████▊  | 785/1000 [02:09&lt;00:24,  8.77it/s] 79%|███████▊  | 786/1000 [02:09&lt;00:25,  8.51it/s] 79%|███████▊  | 787/1000 [02:09&lt;00:26,  8.02it/s] 79%|███████▉  | 788/1000 [02:09&lt;00:30,  6.88it/s] 79%|███████▉  | 789/1000 [02:09&lt;00:29,  7.24it/s] 79%|███████▉  | 790/1000 [02:09&lt;00:27,  7.62it/s] 79%|███████▉  | 791/1000 [02:09&lt;00:26,  7.81it/s] 79%|███████▉  | 792/1000 [02:10&lt;00:26,  7.75it/s] 79%|███████▉  | 793/1000 [02:10&lt;00:27,  7.55it/s] 79%|███████▉  | 794/1000 [02:10&lt;00:27,  7.42it/s] 80%|███████▉  | 795/1000 [02:10&lt;00:27,  7.55it/s] 80%|███████▉  | 796/1000 [02:10&lt;00:26,  7.69it/s] 80%|███████▉  | 797/1000 [02:10&lt;00:26,  7.61it/s] 80%|███████▉  | 798/1000 [02:10&lt;00:27,  7.42it/s] 80%|███████▉  | 799/1000 [02:11&lt;00:29,  6.90it/s] 80%|████████  | 800/1000 [02:11&lt;00:32,  6.18it/s] 80%|████████  | 801/1000 [02:11&lt;00:33,  5.88it/s] 80%|████████  | 802/1000 [02:11&lt;00:34,  5.80it/s] 80%|████████  | 803/1000 [02:11&lt;00:33,  5.92it/s] 80%|████████  | 804/1000 [02:11&lt;00:32,  5.98it/s] 80%|████████  | 805/1000 [02:12&lt;00:31,  6.13it/s] 81%|████████  | 806/1000 [02:12&lt;00:30,  6.28it/s] 81%|████████  | 807/1000 [02:12&lt;00:32,  6.02it/s] 81%|████████  | 808/1000 [02:12&lt;00:31,  6.08it/s] 81%|████████  | 809/1000 [02:12&lt;00:31,  6.08it/s] 81%|████████  | 810/1000 [02:12&lt;00:31,  6.12it/s] 81%|████████  | 811/1000 [02:13&lt;00:31,  6.08it/s] 81%|████████  | 812/1000 [02:13&lt;00:31,  5.98it/s] 81%|████████▏ | 813/1000 [02:13&lt;00:39,  4.71it/s] 81%|████████▏ | 814/1000 [02:13&lt;00:38,  4.81it/s] 82%|████████▏ | 815/1000 [02:14&lt;00:37,  4.89it/s] 82%|████████▏ | 816/1000 [02:14&lt;00:37,  4.90it/s] 82%|████████▏ | 817/1000 [02:14&lt;00:37,  4.88it/s] 82%|████████▏ | 818/1000 [02:14&lt;00:49,  3.69it/s] 82%|████████▏ | 819/1000 [02:15&lt;00:50,  3.60it/s] 82%|████████▏ | 820/1000 [02:15&lt;00:46,  3.89it/s] 82%|████████▏ | 821/1000 [02:15&lt;00:41,  4.34it/s] 82%|████████▏ | 822/1000 [02:15&lt;00:36,  4.85it/s] 82%|████████▏ | 823/1000 [02:15&lt;00:34,  5.18it/s] 82%|████████▏ | 824/1000 [02:16&lt;00:35,  4.98it/s] 82%|████████▎ | 825/1000 [02:16&lt;00:34,  5.01it/s] 83%|████████▎ | 826/1000 [02:16&lt;00:33,  5.16it/s] 83%|████████▎ | 827/1000 [02:16&lt;00:32,  5.36it/s] 83%|████████▎ | 828/1000 [02:16&lt;00:30,  5.58it/s] 83%|████████▎ | 829/1000 [02:16&lt;00:30,  5.69it/s] 83%|████████▎ | 830/1000 [02:17&lt;00:29,  5.77it/s] 83%|████████▎ | 831/1000 [02:17&lt;00:28,  5.99it/s] 83%|████████▎ | 832/1000 [02:17&lt;00:28,  5.90it/s] 83%|████████▎ | 833/1000 [02:17&lt;00:30,  5.49it/s] 83%|████████▎ | 834/1000 [02:17&lt;00:34,  4.86it/s] 84%|████████▎ | 835/1000 [02:18&lt;00:33,  4.97it/s] 84%|████████▎ | 836/1000 [02:18&lt;00:32,  5.12it/s] 84%|████████▎ | 837/1000 [02:18&lt;00:30,  5.32it/s] 84%|████████▍ | 838/1000 [02:18&lt;00:29,  5.57it/s] 84%|████████▍ | 839/1000 [02:18&lt;00:27,  5.81it/s] 84%|████████▍ | 840/1000 [02:18&lt;00:27,  5.91it/s] 84%|████████▍ | 841/1000 [02:19&lt;00:26,  6.02it/s] 84%|████████▍ | 842/1000 [02:19&lt;00:25,  6.27it/s] 84%|████████▍ | 843/1000 [02:19&lt;00:24,  6.34it/s] 84%|████████▍ | 844/1000 [02:19&lt;00:24,  6.40it/s] 84%|████████▍ | 845/1000 [02:19&lt;00:23,  6.52it/s] 85%|████████▍ | 846/1000 [02:19&lt;00:23,  6.53it/s] 85%|████████▍ | 847/1000 [02:19&lt;00:23,  6.53it/s] 85%|████████▍ | 848/1000 [02:20&lt;00:23,  6.54it/s] 85%|████████▍ | 849/1000 [02:20&lt;00:23,  6.35it/s] 85%|████████▌ | 850/1000 [02:20&lt;00:23,  6.44it/s] 85%|████████▌ | 851/1000 [02:20&lt;00:24,  6.06it/s] 85%|████████▌ | 852/1000 [02:20&lt;00:24,  5.94it/s] 85%|████████▌ | 853/1000 [02:20&lt;00:24,  6.11it/s] 85%|████████▌ | 854/1000 [02:21&lt;00:24,  5.95it/s] 86%|████████▌ | 855/1000 [02:21&lt;00:24,  5.95it/s] 86%|████████▌ | 856/1000 [02:21&lt;00:23,  6.03it/s] 86%|████████▌ | 857/1000 [02:21&lt;00:23,  6.10it/s] 86%|████████▌ | 858/1000 [02:21&lt;00:23,  6.08it/s] 86%|████████▌ | 859/1000 [02:21&lt;00:22,  6.40it/s] 86%|████████▌ | 860/1000 [02:22&lt;00:20,  6.78it/s] 86%|████████▌ | 861/1000 [02:22&lt;00:19,  7.21it/s] 86%|████████▌ | 862/1000 [02:22&lt;00:18,  7.47it/s] 86%|████████▋ | 863/1000 [02:22&lt;00:17,  7.67it/s] 86%|████████▋ | 864/1000 [02:22&lt;00:17,  7.82it/s] 86%|████████▋ | 865/1000 [02:22&lt;00:16,  8.07it/s] 87%|████████▋ | 866/1000 [02:22&lt;00:16,  8.20it/s] 87%|████████▋ | 867/1000 [02:22&lt;00:15,  8.43it/s] 87%|████████▋ | 868/1000 [02:22&lt;00:15,  8.58it/s] 87%|████████▋ | 869/1000 [02:23&lt;00:15,  8.50it/s] 87%|████████▋ | 870/1000 [02:23&lt;00:15,  8.53it/s] 87%|████████▋ | 871/1000 [02:23&lt;00:14,  8.64it/s] 87%|████████▋ | 872/1000 [02:23&lt;00:14,  8.78it/s] 87%|████████▋ | 873/1000 [02:23&lt;00:14,  8.76it/s] 87%|████████▋ | 874/1000 [02:23&lt;00:14,  8.78it/s] 88%|████████▊ | 875/1000 [02:23&lt;00:14,  8.74it/s] 88%|████████▊ | 876/1000 [02:23&lt;00:14,  8.78it/s] 88%|████████▊ | 877/1000 [02:24&lt;00:14,  8.77it/s] 88%|████████▊ | 878/1000 [02:24&lt;00:13,  8.80it/s] 88%|████████▊ | 879/1000 [02:24&lt;00:13,  8.82it/s] 88%|████████▊ | 880/1000 [02:24&lt;00:13,  8.84it/s] 88%|████████▊ | 881/1000 [02:24&lt;00:13,  8.74it/s] 88%|████████▊ | 882/1000 [02:24&lt;00:13,  8.56it/s] 88%|████████▊ | 883/1000 [02:24&lt;00:13,  8.56it/s] 88%|████████▊ | 884/1000 [02:24&lt;00:13,  8.66it/s] 88%|████████▊ | 885/1000 [02:24&lt;00:13,  8.68it/s] 89%|████████▊ | 886/1000 [02:25&lt;00:13,  8.65it/s] 89%|████████▊ | 887/1000 [02:25&lt;00:12,  8.72it/s] 89%|████████▉ | 888/1000 [02:25&lt;00:12,  8.72it/s] 89%|████████▉ | 889/1000 [02:25&lt;00:12,  8.76it/s] 89%|████████▉ | 890/1000 [02:25&lt;00:12,  8.71it/s] 89%|████████▉ | 891/1000 [02:25&lt;00:12,  8.71it/s] 89%|████████▉ | 892/1000 [02:25&lt;00:12,  8.77it/s] 89%|████████▉ | 893/1000 [02:25&lt;00:12,  8.73it/s] 89%|████████▉ | 894/1000 [02:25&lt;00:12,  8.64it/s] 90%|████████▉ | 895/1000 [02:26&lt;00:12,  8.58it/s] 90%|████████▉ | 896/1000 [02:26&lt;00:12,  8.58it/s] 90%|████████▉ | 897/1000 [02:26&lt;00:11,  8.60it/s] 90%|████████▉ | 898/1000 [02:26&lt;00:11,  8.63it/s] 90%|████████▉ | 899/1000 [02:26&lt;00:11,  8.59it/s] 90%|█████████ | 900/1000 [02:26&lt;00:11,  8.65it/s] 90%|█████████ | 901/1000 [02:26&lt;00:11,  8.74it/s] 90%|█████████ | 902/1000 [02:26&lt;00:11,  8.76it/s] 90%|█████████ | 903/1000 [02:27&lt;00:11,  8.82it/s] 90%|█████████ | 904/1000 [02:27&lt;00:10,  8.81it/s] 90%|█████████ | 905/1000 [02:27&lt;00:10,  8.75it/s] 91%|█████████ | 906/1000 [02:27&lt;00:10,  8.76it/s] 91%|█████████ | 907/1000 [02:27&lt;00:10,  8.74it/s] 91%|█████████ | 908/1000 [02:27&lt;00:10,  8.67it/s] 91%|█████████ | 909/1000 [02:27&lt;00:10,  8.69it/s] 91%|█████████ | 910/1000 [02:27&lt;00:10,  8.70it/s] 91%|█████████ | 911/1000 [02:27&lt;00:10,  8.75it/s] 91%|█████████ | 912/1000 [02:28&lt;00:09,  8.82it/s] 91%|█████████▏| 913/1000 [02:28&lt;00:09,  8.86it/s] 91%|█████████▏| 914/1000 [02:28&lt;00:09,  8.82it/s] 92%|█████████▏| 915/1000 [02:28&lt;00:09,  8.80it/s] 92%|█████████▏| 916/1000 [02:28&lt;00:09,  8.76it/s] 92%|█████████▏| 917/1000 [02:28&lt;00:09,  8.75it/s] 92%|█████████▏| 918/1000 [02:28&lt;00:09,  8.77it/s] 92%|█████████▏| 919/1000 [02:28&lt;00:09,  8.80it/s] 92%|█████████▏| 920/1000 [02:28&lt;00:09,  8.79it/s] 92%|█████████▏| 921/1000 [02:29&lt;00:08,  8.82it/s] 92%|█████████▏| 922/1000 [02:29&lt;00:08,  8.89it/s] 92%|█████████▏| 923/1000 [02:29&lt;00:08,  8.88it/s] 92%|█████████▏| 924/1000 [02:29&lt;00:08,  8.91it/s] 92%|█████████▎| 925/1000 [02:29&lt;00:08,  8.91it/s] 93%|█████████▎| 926/1000 [02:29&lt;00:08,  8.77it/s] 93%|█████████▎| 927/1000 [02:29&lt;00:08,  8.79it/s] 93%|█████████▎| 928/1000 [02:29&lt;00:08,  8.82it/s] 93%|█████████▎| 929/1000 [02:29&lt;00:08,  8.82it/s] 93%|█████████▎| 930/1000 [02:30&lt;00:07,  8.79it/s] 93%|█████████▎| 931/1000 [02:30&lt;00:07,  8.87it/s] 93%|█████████▎| 932/1000 [02:30&lt;00:07,  8.82it/s] 93%|█████████▎| 933/1000 [02:30&lt;00:07,  8.80it/s] 93%|█████████▎| 934/1000 [02:30&lt;00:07,  8.78it/s] 94%|█████████▎| 935/1000 [02:30&lt;00:07,  8.67it/s] 94%|█████████▎| 936/1000 [02:30&lt;00:07,  8.69it/s] 94%|█████████▎| 937/1000 [02:30&lt;00:07,  8.72it/s] 94%|█████████▍| 938/1000 [02:30&lt;00:07,  8.63it/s] 94%|█████████▍| 939/1000 [02:31&lt;00:07,  8.55it/s] 94%|█████████▍| 940/1000 [02:31&lt;00:07,  8.54it/s] 94%|█████████▍| 941/1000 [02:31&lt;00:06,  8.54it/s] 94%|█████████▍| 942/1000 [02:31&lt;00:06,  8.69it/s] 94%|█████████▍| 943/1000 [02:31&lt;00:06,  8.77it/s] 94%|█████████▍| 944/1000 [02:31&lt;00:06,  8.82it/s] 94%|█████████▍| 945/1000 [02:31&lt;00:06,  8.76it/s] 95%|█████████▍| 946/1000 [02:31&lt;00:06,  8.74it/s] 95%|█████████▍| 947/1000 [02:32&lt;00:06,  8.83it/s] 95%|█████████▍| 948/1000 [02:32&lt;00:05,  8.83it/s] 95%|█████████▍| 949/1000 [02:32&lt;00:05,  8.83it/s] 95%|█████████▌| 950/1000 [02:32&lt;00:05,  8.80it/s] 95%|█████████▌| 951/1000 [02:32&lt;00:05,  8.80it/s] 95%|█████████▌| 952/1000 [02:32&lt;00:05,  8.82it/s] 95%|█████████▌| 953/1000 [02:32&lt;00:05,  8.84it/s] 95%|█████████▌| 954/1000 [02:32&lt;00:05,  8.85it/s] 96%|█████████▌| 955/1000 [02:32&lt;00:05,  8.83it/s] 96%|█████████▌| 956/1000 [02:33&lt;00:05,  8.79it/s] 96%|█████████▌| 957/1000 [02:33&lt;00:04,  8.80it/s] 96%|█████████▌| 958/1000 [02:33&lt;00:04,  8.78it/s] 96%|█████████▌| 959/1000 [02:33&lt;00:04,  8.76it/s] 96%|█████████▌| 960/1000 [02:33&lt;00:04,  8.71it/s] 96%|█████████▌| 961/1000 [02:33&lt;00:04,  8.69it/s] 96%|█████████▌| 962/1000 [02:33&lt;00:04,  8.71it/s] 96%|█████████▋| 963/1000 [02:33&lt;00:04,  8.79it/s] 96%|█████████▋| 964/1000 [02:33&lt;00:04,  8.86it/s] 96%|█████████▋| 965/1000 [02:34&lt;00:03,  8.85it/s] 97%|█████████▋| 966/1000 [02:34&lt;00:03,  8.80it/s] 97%|█████████▋| 967/1000 [02:34&lt;00:03,  8.81it/s] 97%|█████████▋| 968/1000 [02:34&lt;00:03,  8.79it/s] 97%|█████████▋| 969/1000 [02:34&lt;00:03,  8.87it/s] 97%|█████████▋| 970/1000 [02:34&lt;00:03,  8.79it/s] 97%|█████████▋| 971/1000 [02:34&lt;00:03,  8.84it/s] 97%|█████████▋| 972/1000 [02:34&lt;00:03,  8.95it/s] 97%|█████████▋| 973/1000 [02:34&lt;00:03,  8.84it/s] 97%|█████████▋| 974/1000 [02:35&lt;00:02,  8.85it/s] 98%|█████████▊| 975/1000 [02:35&lt;00:02,  8.68it/s] 98%|█████████▊| 976/1000 [02:35&lt;00:02,  8.78it/s] 98%|█████████▊| 977/1000 [02:35&lt;00:02,  8.80it/s] 98%|█████████▊| 978/1000 [02:35&lt;00:02,  8.78it/s] 98%|█████████▊| 979/1000 [02:35&lt;00:02,  8.61it/s] 98%|█████████▊| 980/1000 [02:35&lt;00:02,  8.65it/s] 98%|█████████▊| 981/1000 [02:35&lt;00:02,  8.74it/s] 98%|█████████▊| 982/1000 [02:36&lt;00:02,  8.60it/s] 98%|█████████▊| 983/1000 [02:36&lt;00:02,  8.33it/s] 98%|█████████▊| 984/1000 [02:36&lt;00:01,  8.23it/s] 98%|█████████▊| 985/1000 [02:36&lt;00:01,  8.35it/s] 99%|█████████▊| 986/1000 [02:36&lt;00:01,  8.50it/s] 99%|█████████▊| 987/1000 [02:36&lt;00:01,  8.56it/s] 99%|█████████▉| 988/1000 [02:36&lt;00:01,  8.64it/s] 99%|█████████▉| 989/1000 [02:36&lt;00:01,  8.61it/s] 99%|█████████▉| 990/1000 [02:36&lt;00:01,  8.62it/s] 99%|█████████▉| 991/1000 [02:37&lt;00:01,  8.72it/s] 99%|█████████▉| 992/1000 [02:37&lt;00:00,  8.77it/s] 99%|█████████▉| 993/1000 [02:37&lt;00:00,  8.76it/s] 99%|█████████▉| 994/1000 [02:37&lt;00:00,  8.75it/s]100%|█████████▉| 995/1000 [02:37&lt;00:00,  8.65it/s]100%|█████████▉| 996/1000 [02:37&lt;00:00,  8.64it/s]100%|█████████▉| 997/1000 [02:37&lt;00:00,  8.51it/s]100%|█████████▉| 998/1000 [02:37&lt;00:00,  8.65it/s]100%|█████████▉| 999/1000 [02:37&lt;00:00,  8.74it/s]100%|██████████| 1000/1000 [02:38&lt;00:00,  8.83it/s]100%|██████████| 1000/1000 [02:38&lt;00:00,  6.32it/s]\n\n\nH0                                      X1=0\nri-type                      randomization-c\nEstimate                 -0.9929357698186859\nPr(&gt;|t|)                                 0.0\nStd. Error (Pr(&gt;|t|))                    0.0\n2.5% (Pr(&gt;|t|))                          0.0\n97.5% (Pr(&gt;|t|))                         0.0\ndtype: object\n\n\n\n\n\nse\nestimation.feols_.Feols.se()\nFitted model standard errors.\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.Series\nA pd.Series with the standard errors of the estimated regression model.\n\n\n\n\n\n\ntidy\nestimation.feols_.Feols.tidy(alpha=None)\nTidy model outputs.\nReturn a tidy pd.DataFrame with the point estimates, standard errors, t-statistics, and p-values.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nalpha\nOptional[float]\nThe significance level for the confidence intervals. If None, computes a 95% confidence interval (alpha = 0.05).\nNone\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\ntidy_df\npd.DataFrame\nA tidy pd.DataFrame containing the regression results, including point estimates, standard errors, t-statistics, and p-values.\n\n\n\n\n\n\nto_array\nestimation.feols_.Feols.to_array()\nConvert estimation data frames to np arrays.\n\n\ntstat\nestimation.feols_.Feols.tstat()\nFitted model t-statistics.\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.Series\nA pd.Series with t-statistics of the estimated regression model.\n\n\n\n\n\n\nupdate\nestimation.feols_.Feols.update(X_new, y_new, inplace=False)\nUpdate coefficients for new observations using Sherman-Morrison formula.\n\nReturns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nUpdated coefficients\n\n\n\n\n\n\nvcov\nestimation.feols_.Feols.vcov(vcov, data=None)\nCompute covariance matrices for an estimated regression model.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nvcov\nUnion[str, dict[str, str]]\nA string or dictionary specifying the type of variance-covariance matrix to use for inference. If a string, it can be one of “iid”, “hetero”, “HC1”, “HC2”, “HC3”. If a dictionary, it should have the format {“CRV1”: “clustervar”} for CRV1 inference or {“CRV3”: “clustervar”} for CRV3 inference. Note that CRV3 inference is currently not supported for IV estimation.\nrequired\n\n\ndata\nOptional[DataFrameType]\nThe data used for estimation. If None, tries to fetch the data from the model object. Defaults to None.\nNone\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nFeols\nAn instance of class [Feols(/reference/Feols.qmd) with updated inference.\n\n\n\n\n\n\nwald_test\nestimation.feols_.Feols.wald_test(R=None, q=None, distribution='F')\nConduct Wald test.\nCompute a Wald test for a linear hypothesis of the form R * β = q. where R is m x k matrix, β is a k x 1 vector of coefficients, and q is m x 1 vector. By default, tests the joint null hypothesis that all coefficients are zero.\nThis method producues the following attriutes\n_dfd : int degree of freedom in denominator _dfn : int degree of freedom in numerator _wald_statistic : scalar Wald-statistics computed for hypothesis testing _f_statistic : scalar Wald-statistics(when R is an indentity matrix, and q being zero vector) computed for hypothesis testing _p_value : scalar corresponding p-value for statistics\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nR\narray - like\nThe matrix R of the linear hypothesis. If None, defaults to an identity matrix.\nNone\n\n\nq\narray - like\nThe vector q of the linear hypothesis. If None, defaults to a vector of zeros.\nNone\n\n\ndistribution\nstr\nThe distribution to use for the p-value. Can be either “F” or “chi2”. Defaults to “F”.\n'F'\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.Series\nA pd.Series with the Wald statistic and p-value.\n\n\n\n\n\nExamples\n\nimport numpy as np\nimport pandas as pd\nimport pyfixest as pf\n\ndata = pf.get_data()\nfit = pf.feols(\"Y ~ X1 + X2| f1\", data, vcov={\"CRV1\": \"f1\"}, ssc=pf.ssc(adj=False))\n\nR = np.array([[1,-1]] )\nq = np.array([0.0])\n\n# Wald test\nfit.wald_test(R=R, q=q, distribution = \"chi2\")\nf_stat = fit._f_statistic\np_stat = fit._p_value\n\nprint(f\"Python f_stat: {f_stat}\")\nprint(f\"Python p_stat: {p_stat}\")\n\nPython f_stat: 126.4065047404348\nPython p_stat: 2.505309282814187e-29\n\n\n\n\n\nwildboottest\nestimation.feols_.Feols.wildboottest(\n    reps,\n    cluster=None,\n    param=None,\n    weights_type='rademacher',\n    impose_null=True,\n    bootstrap_type='11',\n    seed=None,\n    adj=True,\n    cluster_adj=True,\n    parallel=False,\n    return_bootstrapped_t_stats=False,\n)\nRun a wild cluster bootstrap based on an object of type “Feols”.\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nreps\nint\nThe number of bootstrap iterations to run.\nrequired\n\n\ncluster\nUnion[str, None]\nThe variable used for clustering. Defaults to None. If None, then uses the variable specified in the model’s clustervar attribute. If no _clustervar attribute is found, runs a heteroskedasticity- robust bootstrap.\nNone\n\n\nparam\nUnion[str, None]\nA string of length one, containing the test parameter of interest. Defaults to None.\nNone\n\n\nweights_type\nstr\nThe type of bootstrap weights. Options are ‘rademacher’, ‘mammen’, ‘webb’, or ‘normal’. Defaults to ‘rademacher’.\n'rademacher'\n\n\nimpose_null\nbool\nIndicates whether to impose the null hypothesis on the bootstrap DGP. Defaults to True.\nTrue\n\n\nbootstrap_type\nstr\nA string of length one to choose the bootstrap type. Options are ‘11’, ‘31’, ‘13’, or ‘33’. Defaults to ‘11’.\n'11'\n\n\nseed\nUnion[int, None]\nAn option to provide a random seed. Defaults to None.\nNone\n\n\nadj\nbool\nIndicates whether to apply a small sample adjustment for the number of observations and covariates. Defaults to True.\nTrue\n\n\ncluster_adj\nbool\nIndicates whether to apply a small sample adjustment for the number of clusters. Defaults to True.\nTrue\n\n\nparallel\nbool\nIndicates whether to run the bootstrap in parallel. Defaults to False.\nFalse\n\n\nseed\nUnion[str, None]\nAn option to provide a random seed. Defaults to None.\nNone\n\n\nreturn_bootstrapped_t_stats\nbool, optional:\nIf True, the method returns a tuple of the regular output and the bootstrapped t-stats. Defaults to False.\nFalse\n\n\n\n\n\nReturns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.DataFrame\nA DataFrame with the original, non-bootstrapped t-statistic and bootstrapped p-value, along with the bootstrap type, inference type (HC vs CRV), and whether the null hypothesis was imposed on the bootstrap DGP. If return_bootstrapped_t_stats is True, the method returns a tuple of the regular output and the bootstrapped t-stats.\n\n\n\n\n\nExamples\n\nimport re\nimport pyfixest as pf\n\ndata = pf.get_data()\nfit = pf.feols(\"Y ~ X1 + X2 | f1\", data)\n\nfit.wildboottest(\n    param = \"X1\",\n    reps=1000,\n    seed = 822\n)\n\nfit.wildboottest(\n    param = \"X1\",\n    reps=1000,\n    seed = 822,\n    bootstrap_type = \"31\"\n)\n\nparam                              X1\nt value           -14.056663479651508\nPr(&gt;|t|)                          0.0\nbootstrap_type                     31\ninference                     CRV(f1)\nimpose_null                      True\nssc                          1.067715\ndtype: object\n\n\n\n\n\nwls_transform\nestimation.feols_.Feols.wls_transform()\nTransform model matrices for WLS Estimation.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feols_.Feols"
    ]
  },
  {
    "objectID": "reference/estimation.feiv_.Feiv.html",
    "href": "reference/estimation.feiv_.Feiv.html",
    "title": "estimation.feiv_.Feiv",
    "section": "",
    "text": "estimation.feiv_.Feiv(\n    self,\n    FixestFormula,\n    data,\n    ssc_dict,\n    drop_singletons,\n    drop_intercept,\n    weights,\n    weights_type,\n    collin_tol,\n    fixef_tol,\n    lookup_demeaned_data,\n    solver='np.linalg.solve',\n    demeaner_backend='numba',\n    store_data=True,\n    copy_data=True,\n    lean=False,\n    context=0,\n    sample_split_var=None,\n    sample_split_value=None,\n)\nNon user-facing class to estimate an IV model using a 2SLS estimator.\nInherits from the Feols class. Users should not directly instantiate this class, but rather use the feols() function. Note that no demeaning is performed in this class: demeaning is performed in the FixestMulti class (to allow for caching of demeaned variables for multiple estimation).",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feiv_.Feiv"
    ]
  },
  {
    "objectID": "reference/estimation.feiv_.Feiv.html#parameters",
    "href": "reference/estimation.feiv_.Feiv.html#parameters",
    "title": "estimation.feiv_.Feiv",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nY\nnp.ndarray\nDependent variable, a two-dimensional np.array.\nrequired\n\n\nX\nnp.ndarray\nIndependent variables, a two-dimensional np.array.\nrequired\n\n\nendgvar\nnp.ndarray\nEndogenous Indenpendent variables, a two-dimensional np.array.\nrequired\n\n\nZ\nnp.ndarray\nInstruments, a two-dimensional np.array.\nrequired\n\n\nweights\nnp.ndarray\nWeights, a one-dimensional np.array.\nrequired\n\n\ncoefnames_x\nlist\nNames of the coefficients of X.\nrequired\n\n\ncoefnames_z\nlist\nNames of the coefficients of Z.\nrequired\n\n\ncollin_tol\nfloat\nTolerance for collinearity check.\nrequired\n\n\nsolver\nLiteral['np.linalg.lstsq', 'np.linalg.solve', 'scipy.sparse.linalg.lsqr', 'jax']\ndefault is ‘np.linalg.solve’. Solver to use for the estimation.\n'np.linalg.solve'\n\n\ndemeaner_backend\nLiteral['numba', 'jax']\nThe backend used for demeaning.\n'numba'\n\n\nweights_name\nOptional[str]\nName of the weights variable.\nrequired\n\n\nweights_type\nOptional[str]\nType of the weights variable. Either “aweights” for analytic weights or “fweights” for frequency weights.\nrequired",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feiv_.Feiv"
    ]
  },
  {
    "objectID": "reference/estimation.feiv_.Feiv.html#attributes",
    "href": "reference/estimation.feiv_.Feiv.html#attributes",
    "title": "estimation.feiv_.Feiv",
    "section": "Attributes",
    "text": "Attributes\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n_Z\nnp.ndarray\nProcessed instruments after handling multicollinearity.\n\n\n_weights_type_feiv\nstr\nType of the weights variable defined in Feiv class. Either “aweights” for analytic weights or “fweights” for frequency weights.\n\n\n_coefnames_z\nlist\nNames of coefficients for Z after handling multicollinearity.\n\n\n_collin_vars_z\nlist\nVariables identified as collinear in Z.\n\n\n_collin_index_z\nlist\nIndices of collinear variables in Z.\n\n\n_is_iv\nbool\nIndicator if instrumental variables are used.\n\n\n_support_crv3_inference\nbool\nIndicator for supporting CRV3 inference.\n\n\n_support_iid_inference\nbool\nIndicator for supporting IID inference.\n\n\n_tZX\nnp.ndarray\nTranspose of Z times X.\n\n\n_tXZ\nnp.ndarray\nTranspose of X times Z.\n\n\n_tZy\nnp.ndarray\nTranspose of Z times Y.\n\n\n_tZZinv\nnp.ndarray\nInverse of transpose of Z times Z.\n\n\n_beta_hat\nnp.ndarray\nEstimated regression coefficients.\n\n\n_Y_hat_link\nnp.ndarray\nPredicted values of the regression model.\n\n\n_u_hat\nnp.ndarray\nResiduals of the regression model.\n\n\n_scores\nnp.ndarray\nScores used in the regression.\n\n\n_hessian\nnp.ndarray\nHessian matrix used in the regression.\n\n\n_bread\nnp.ndarray\nBread matrix used in the regression.\n\n\n_pi_hat\nnp.ndarray\nEstimated coefficients from 1st stage regression\n\n\n_X_hat\nnp.ndarray\nPredicted values of the 1st stage regression\n\n\n_v_hat\nnp.ndarray\nResiduals of the 1st stage regression\n\n\n_model_1st_stage\nAny\nfeols object of 1st stage regression. It contains various results and diagnostics from the fixed effects OLS regression.\n\n\n_endogvar_1st_stage\nnp.ndarray\nUnweihgted Endogenous independent variable vector\n\n\n_Z_1st_stage\nnp.ndarray\nUnweighted instruments vector to be used for 1st stage\n\n\n_non_exo_instruments\nlist\nList of instruments name excluding exogenous independent vars.\n\n\n__p_iv\nscalar\nNumber of instruments listed in _non_exo_instruments\n\n\n_f_stat_1st_stage\nscalar\nF-statistics of First Stage regression for evaluation of IV weakness. The computed F-statistics test the following null hypothesis : # H0 : β_{z_1} = 0 & … & β_{z_{p_iv}} = 0 where z_1, …, z_{p_iv} # are the instrument variables # H1 : H0 does not hold Note that this F-statistics is adjusted to heteroskedasticity / clusters if users set specification of variance-covariance matrix type\n\n\n_eff_F\nscalar\nEffective F-statistics of first stage regression as in Olea and Pflueger 2013\n\n\n_data\npd.DataFrame\nThe data frame used in the estimation. None if arguments lean = True or store_data = False.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feiv_.Feiv"
    ]
  },
  {
    "objectID": "reference/estimation.feiv_.Feiv.html#raises",
    "href": "reference/estimation.feiv_.Feiv.html#raises",
    "title": "estimation.feiv_.Feiv",
    "section": "Raises",
    "text": "Raises\n\n\n\nName\nType\nDescription\n\n\n\n\n\nValueError\nIf Z is not a two-dimensional array.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feiv_.Feiv"
    ]
  },
  {
    "objectID": "reference/estimation.feiv_.Feiv.html#methods",
    "href": "reference/estimation.feiv_.Feiv.html#methods",
    "title": "estimation.feiv_.Feiv",
    "section": "Methods",
    "text": "Methods\n\n\n\nName\nDescription\n\n\n\n\nIV_Diag\nImplement IV diagnostic tests.\n\n\nIV_weakness_test\nImplement IV weakness test (F-test).\n\n\ndemean\nDemean instruments and endogeneous variable.\n\n\ndrop_multicol_vars\nDrop multicollinear variables in matrix of instruments Z.\n\n\neff_F\nCompute Effective F stat (Olea and Pflueger 2013).\n\n\nfirst_stage\nImplement First stage regression.\n\n\nget_fit\nFit a IV model using a 2SLS estimator.\n\n\nto_array\nTransform estimation DataFrames to arrays.\n\n\nwls_transform\nTransform variables for WLS estimation.\n\n\n\n\nIV_Diag\nestimation.feiv_.Feiv.IV_Diag(statistics=None)\nImplement IV diagnostic tests.\n\nNotes\nThis method covers diagnostic tests related with IV regression. We currently have IV weak tests only. More test will be updated in future updates!\n\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nstatistics\nlist[str]\nList of IV diagnostic statistics\nNone\n\n\n\n\n\nExample\nThe following is an example usage of this method:\n::: {#1e7be3e9 .cell execution_count=1}\n``` {.python .cell-code}\nimport numpy as np\nimport pandas as pd\nfrom pyfixest.estimation.estimation import feols\n\n# Set random seed for reproducibility\nnp.random.seed(1)\n\n# Number of observations\nn = 1000\n\n# Simulate the data\n# Instrumental variable\nz = np.random.binomial(1, 0.5, size=n)\nz2 = np.random.binomial(1, 0.5, size=n)\n\n# Endogenous variable\nd = 0.5 * z + 1.5 * z2 + np.random.normal(size=n)\n\n# Control variables\nc1 = np.random.normal(size=n)\nc2 = np.random.normal(size=n)\n\n# Outcome variable\ny = 1.0 + 1.5 * d + 0.8 * c1 + 0.5 * c2 + np.random.normal(size=n)\n\n# Cluster variable\ncluster = np.random.randint(1, 50, size=n)\nweights = np.random.uniform(1, 3, size=n)\n\n# Create a DataFrame\ndata = pd.DataFrame({\n    'd': d,\n    'y': y,\n    'z': z,\n    'z2': z2,\n    'c1': c1,\n    'c2': c2,\n    'cluster': cluster,\n    'weights': weights\n})\n\nvcov_detail = \"iid\"\n\n# Fit OLS model\nfit_ols = feols(\"y ~ 1 + d + c1 + c2\", data=data, vcov=vcov_detail)\n\n# Fit IV model\nfit_iv = feols(\"y ~ 1 + c1 + c2 | d ~ z\", data=data,\n         vcov=vcov_detail,\n         weights=\"weights\")\nfit_iv.first_stage()\nF_stat_pf = fit_iv._f_stat_1st_stage\nfit_iv.IV_Diag()\nF_stat_eff_pf = fit_iv._eff_F\n\nprint(\"(Unadjusted) F stat :\", F_stat_pf)\nprint(\"Effective F stat :\", F_stat_eff_pf)\n```\n\n::: {.cell-output .cell-output-display}\n\n```{=html}\n\n            &lt;div id=\"q2KxOp\"&gt;&lt;/div&gt;\n            &lt;script type=\"text/javascript\" data-lets-plot-script=\"library\"&gt;\n                if(!window.letsPlotCallQueue) {\n                    window.letsPlotCallQueue = [];\n                }; \n                window.letsPlotCall = function(f) {\n                    window.letsPlotCallQueue.push(f);\n                };\n                (function() {\n                    var script = document.createElement(\"script\");\n                    script.type = \"text/javascript\";\n                    script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v4.5.2/js-package/distr/lets-plot.min.js\";\n                    script.onload = function() {\n                        window.letsPlotCall = function(f) {f();};\n                        window.letsPlotCallQueue.forEach(function(f) {f();});\n                        window.letsPlotCallQueue = [];\n                        \n                    };\n                    script.onerror = function(event) {\n                        window.letsPlotCall = function(f) {};    // noop\n                        window.letsPlotCallQueue = [];\n                        var div = document.createElement(\"div\");\n                        div.style.color = 'darkred';\n                        div.textContent = 'Error loading Lets-Plot JS';\n                        document.getElementById(\"q2KxOp\").appendChild(div);\n                    };\n                    var e = document.getElementById(\"q2KxOp\");\n                    e.appendChild(script);\n                })()\n            &lt;/script&gt;\n            \n```\n\n:::\n\n::: {.cell-output .cell-output-display}\n\n```{=html}\n\n            &lt;div id=\"61hXlY\"&gt;&lt;/div&gt;\n            &lt;script type=\"text/javascript\" data-lets-plot-script=\"library\"&gt;\n                if(!window.letsPlotCallQueue) {\n                    window.letsPlotCallQueue = [];\n                }; \n                window.letsPlotCall = function(f) {\n                    window.letsPlotCallQueue.push(f);\n                };\n                (function() {\n                    var script = document.createElement(\"script\");\n                    script.type = \"text/javascript\";\n                    script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v4.5.2/js-package/distr/lets-plot.min.js\";\n                    script.onload = function() {\n                        window.letsPlotCall = function(f) {f();};\n                        window.letsPlotCallQueue.forEach(function(f) {f();});\n                        window.letsPlotCallQueue = [];\n                        \n                    };\n                    script.onerror = function(event) {\n                        window.letsPlotCall = function(f) {};    // noop\n                        window.letsPlotCallQueue = [];\n                        var div = document.createElement(\"div\");\n                        div.style.color = 'darkred';\n                        div.textContent = 'Error loading Lets-Plot JS';\n                        document.getElementById(\"61hXlY\").appendChild(div);\n                    };\n                    var e = document.getElementById(\"61hXlY\");\n                    e.appendChild(script);\n                })()\n            &lt;/script&gt;\n            \n```\n\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n(Unadjusted) F stat : 52.815355604575046\nEffective F stat : 48.612881198587125\n```\n:::\n:::\n\n\n\nIV_weakness_test\nestimation.feiv_.Feiv.IV_weakness_test(iv_diag_statistics=None)\nImplement IV weakness test (F-test).\nThis method covers hetero-robust and clustered-robust F statistics. It produces two statistics:\n\nself._f_stat_1st_stage: F statistics of first stage regression\nself._eff_F: Effective F statistics (Olea and Pflueger 2013) of first stage regression\n\n\nNotes\n“self._f_stat_1st_stage” is adjusted to the specification of vcov. If vcov_detail = “iid”, F statistics is not adjusted, otherwise it is always adjusted.\n\n\nParameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\niv_diag_statistics\nlist\nList of IV weakness statistics\nNone\n\n\n\n\n\n\ndemean\nestimation.feiv_.Feiv.demean()\nDemean instruments and endogeneous variable.\n\n\ndrop_multicol_vars\nestimation.feiv_.Feiv.drop_multicol_vars()\nDrop multicollinear variables in matrix of instruments Z.\n\n\neff_F\nestimation.feiv_.Feiv.eff_F()\nCompute Effective F stat (Olea and Pflueger 2013).\n\n\nfirst_stage\nestimation.feiv_.Feiv.first_stage()\nImplement First stage regression.\n\n\nget_fit\nestimation.feiv_.Feiv.get_fit()\nFit a IV model using a 2SLS estimator.\n\n\nto_array\nestimation.feiv_.Feiv.to_array()\nTransform estimation DataFrames to arrays.\n\n\nwls_transform\nestimation.feiv_.Feiv.wls_transform()\nTransform variables for WLS estimation.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feiv_.Feiv"
    ]
  },
  {
    "objectID": "reference/estimation.fegaussian_.Fegaussian.html",
    "href": "reference/estimation.fegaussian_.Fegaussian.html",
    "title": "estimation.fegaussian_.Fegaussian",
    "section": "",
    "text": "estimation.fegaussian_.Fegaussian\nestimation.fegaussian_.Fegaussian(\n    self,\n    FixestFormula,\n    data,\n    ssc_dict,\n    drop_singletons,\n    drop_intercept,\n    weights,\n    weights_type,\n    collin_tol,\n    fixef_tol,\n    lookup_demeaned_data,\n    tol,\n    maxiter,\n    solver,\n    store_data=True,\n    copy_data=True,\n    lean=False,\n    sample_split_var=None,\n    sample_split_value=None,\n    separation_check=None,\n    context=0,\n)\nClass for the estimation of a fixed-effects GLM with normal errors.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.fegaussian_.Fegaussian"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.feols.html",
    "href": "reference/estimation.estimation.feols.html",
    "title": "estimation.estimation.feols",
    "section": "",
    "text": "estimation.estimation.feols(\n    fml,\n    data,\n    vcov=None,\n    weights=None,\n    ssc=None,\n    fixef_rm='none',\n    fixef_tol=1e-08,\n    collin_tol=1e-10,\n    drop_intercept=False,\n    i_ref1=None,\n    copy_data=True,\n    store_data=True,\n    lean=False,\n    weights_type='aweights',\n    solver='np.linalg.solve',\n    demeaner_backend='numba',\n    use_compression=False,\n    reps=100,\n    context=None,\n    seed=None,\n    split=None,\n    fsplit=None,\n)\nEstimate a linear regression models with fixed effects using fixest formula syntax.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.feols"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.feols.html#parameters",
    "href": "reference/estimation.estimation.feols.html#parameters",
    "title": "estimation.estimation.feols",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfml\nstr\nA three-sided formula string using fixest formula syntax. Syntax: “Y ~ X1 + X2 | FE1 + FE2 | X1 ~ Z1”. “|” separates dependent variable, fixed effects, and instruments. Special syntax includes stepwise regressions, cumulative stepwise regression, multiple dependent variables, interaction of variables (i(X1,X2)), and interacted fixed effects (fe1^fe2).\nrequired\n\n\ndata\nDataFrameType\nA pandas or polars dataframe containing the variables in the formula.\nrequired\n\n\nvcov\nUnion[VcovTypeOptions, dict[str, str]]\nType of variance-covariance matrix for inference. Options include “iid”, “hetero”, “HC1”, “HC2”, “HC3”, or a dictionary for CRV1/CRV3 inference.\nNone\n\n\nweights\nUnion[None, str], optional.\nDefault is None. Weights for WLS estimation. If None, all observations are weighted equally. If a string, the name of the column in data that contains the weights.\nNone\n\n\nssc\nstr\nA ssc object specifying the small sample correction for inference.\nNone\n\n\nfixef_rm\nFixedRmOptions\nSpecifies whether to drop singleton fixed effects. Options: “none” (default), “singleton”.\n'none'\n\n\ncollin_tol\nfloat\nTolerance for collinearity check, by default 1e-10.\n1e-10\n\n\nfixef_tol\n\nTolerance for the fixed effects demeaning algorithm. Defaults to 1e-08.\n1e-08\n\n\ndrop_intercept\nbool\nWhether to drop the intercept from the model, by default False.\nFalse\n\n\ni_ref1\n\nDeprecated with pyfixest version 0.18.0. Please use i-syntax instead, i.e. feols(‘Y~ i(f1, ref=1)’, data = data) instead of the former feols(‘Y~ i(f1)’, data = data, i_ref=1).\nNone\n\n\ncopy_data\nbool\nWhether to copy the data before estimation, by default True. If set to False, the data is not copied, which can save memory but may lead to unintended changes in the input data outside of fepois. For example, the input data set is re-index within the function. As far as I know, the only other relevant case is when using interacted fixed effects, in which case you’ll find a column with interacted fixed effects in the data set.\nTrue\n\n\nstore_data\nbool\nWhether to store the data in the model object, by default True. If set to False, the data is not stored in the model object, which can improve performance and save memory. However, it will no longer be possible to access the data via the data attribute of the model object. This has impact on post-estimation capabilities that rely on the data, e.g. predict() or vcov().\nTrue\n\n\nlean\nbool\nFalse by default. If True, then all large objects are removed from the returned result: this will save memory but will block the possibility to use many methods. It is recommended to use the argument vcov to obtain the appropriate standard-errors at estimation time, since obtaining different SEs won’t be possible afterwards.\nFalse\n\n\nweights_type\nWeightsTypeOptions\nOptions include aweights or fweights. aweights implement analytic or precision weights, while fweights implement frequency weights. For details see this blog post: https://notstatschat.rbind.io/2020/08/04/weights-in-statistics/.\n'aweights'\n\n\nsolver\nSolverOptions, optional.\nThe solver to use for the regression. Can be either “np.linalg.solve” or “np.linalg.lstsq”. Defaults to “np.linalg.solve”.\n'np.linalg.solve'\n\n\ndemeaner_backend\nDemeanerBackendOptions\nThe backend to use for demeaning. Can be either “numba” or “jax”. Defaults to “numba”.\n'numba'\n\n\nuse_compression\nbool\nWhether to use sufficient statistics to losslessly fit the regression model on compressed data. False by default. If True, the model is estimated on compressed data, which can lead to a significant speed-up for large data sets. See the paper by Wong et al (2021) for more details https://arxiv.org/abs/2102.11297. Note that if use_compression = True, inference is lossless. If standard errors are clustered, a wild cluster bootstrap is employed. Parameters for the wild bootstrap can be specified via the reps and seed arguments. Additionally, note that for one-way fixed effects, the estimation method uses a Mundlak transform to “control” for the fixed effects. For two-way fixed effects, a two-way Mundlak transform is employed. For two-way fixed effects, the Mundlak transform is only identical to a two-way fixed effects model if the data set is a panel. We do not provide any checks for the panel status of the data set.\nFalse\n\n\nreps\nint\nNumber of bootstrap repetitions. Only relevant for boostrap inference applied to compute cluster robust errors when use_compression = True.\n100\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\nNone\n\n\nseed\nOptional[int]\nSeed for the random number generator. Only relevant for boostrap inference applied to compute cluster robust errors when use_compression = True.\nNone\n\n\nsplit\nOptional[str]\nA character string, i.e. ‘split = var’. If provided, the sample is split according to the variable and one estimation is performed for each value of that variable. If you also want to include the estimation for the full sample, use the argument fsplit instead.\nNone\n\n\nfsplit\nOptional[str]\nThis argument is the same as split but also includes the full sample as the first estimation.\nNone",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.feols"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.feols.html#returns",
    "href": "reference/estimation.estimation.feols.html#returns",
    "title": "estimation.estimation.feols",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nobject\nAn instance of the [Feols(/reference/Feols.qmd) class or FixestMulti class for multiple models specified via fml.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.feols"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.feols.html#examples",
    "href": "reference/estimation.estimation.feols.html#examples",
    "title": "estimation.estimation.feols",
    "section": "Examples",
    "text": "Examples\nAs in fixest, the [Feols(/reference/Feols.qmd) function can be used to estimate a simple linear regression model with fixed effects. The following example regresses Y on X1 and X2 with fixed effects for f1 and f2: fixed effects are specified after the | symbol.\n\nimport pyfixest as pf\nimport pandas as pd\nimport numpy as np\n\ndata = pf.get_data()\n\nfit = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data)\nfit.summary()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: f1+f2\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.924 |        0.061 |   -15.165 |      0.000 | -1.049 |  -0.799 |\n| X2            |     -0.174 |        0.015 |   -11.918 |      0.000 | -0.204 |  -0.144 |\n---\nRMSE: 1.346 R2: 0.659 R2 Within: 0.303 \n\n\nCalling feols() returns an instance of the [Feols(/reference/Feols.qmd) class. The summary() method can be used to print the results.\nAn alternative way to retrieve model results is via the tidy() method, which returns a pandas dataframe with the estimated coefficients, standard errors, t-statistics, and p-values.\n\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n-0.924046\n0.060934\n-15.164621\n2.664535e-15\n-1.048671\n-0.799421\n\n\nX2\n-0.174107\n0.014608\n-11.918277\n1.069367e-12\n-0.203985\n-0.144230\n\n\n\n\n\n\n\nYou can also access all elements in the tidy data frame by dedicated methods, e.g. fit.coef() for the coefficients, fit.se() for the standard errors, fit.tstat() for the t-statistics, and fit.pval() for the p-values, and fit.confint() for the confidence intervals.\nThe employed type of inference can be specified via the vcov argument. If vcov is not provided, PyFixest employs the fixest default of iid inference, unless there are fixed effects in the model, in which case feols() clusters the standard error by the first fixed effect (CRV1 inference).\n\nfit1 = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data, vcov=\"iid\")\nfit2 = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data, vcov=\"hetero\")\nfit3 = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data, vcov={\"CRV1\": \"f1\"})\n\nSupported inference types are “iid”, “hetero”, “HC1”, “HC2”, “HC3”, and “CRV1”/“CRV3”. Clustered standard errors are specified via a dictionary, e.g. {\"CRV1\": \"f1\"} for CRV1 inference with clustering by f1 or {\"CRV3\": \"f1\"} for CRV3 inference with clustering by f1. For two-way clustering, you can provide a formula string, e.g. {\"CRV1\": \"f1 + f2\"} for CRV1 inference with clustering by f1.\n\nfit4 = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data, vcov={\"CRV1\": \"f1 + f2\"})\n\nInference can be adjusted post estimation via the vcov method:\n\nfit.summary()\nfit.vcov(\"iid\").summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: f1+f2\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.924 |        0.061 |   -15.165 |      0.000 | -1.049 |  -0.799 |\n| X2            |     -0.174 |        0.015 |   -11.918 |      0.000 | -0.204 |  -0.144 |\n---\nRMSE: 1.346 R2: 0.659 R2 Within: 0.303 \n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: f1+f2\nInference:  iid\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.924 |        0.054 |   -16.995 |      0.000 | -1.031 |  -0.817 |\n| X2            |     -0.174 |        0.014 |   -12.081 |      0.000 | -0.202 |  -0.146 |\n---\nRMSE: 1.346 R2: 0.659 R2 Within: 0.303 \n\n\nThe ssc argument specifies the small sample correction for inference. In general, feols() uses all of fixest::feols() defaults, but sets the fixef.K argument to \"none\" whereas the fixest::feols() default is \"nested\". See here for more details: link to github.\nfeols() supports a range of multiple estimation syntax, i.e. you can estimate multiple models in one call. The following example estimates two models, one with fixed effects for f1 and one with fixed effects for f2 using the sw() syntax.\n\nfit = pf.feols(\"Y ~ X1 + X2 | sw(f1, f2)\", data)\ntype(fit)\n\npyfixest.estimation.FixestMulti_.FixestMulti\n\n\nThe returned object is an instance of the FixestMulti class. You can access the results of the first model via fit.fetch_model(0) and the results of the second model via fit.fetch_model(1). You can compare the model results via the etable() function:\n\npf.etable(fit)\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n\n\n\n\ncoef\n\n\nX1\n-0.950***\n(0.067)\n-0.979***\n(0.077)\n\n\nX2\n-0.174***\n(0.018)\n-0.175***\n(0.022)\n\n\nfe\n\n\nf2\n-\nx\n\n\nf1\nx\n-\n\n\nstats\n\n\nObservations\n997\n998\n\n\nS.E. type\nby: f1\nby: f2\n\n\nR2\n0.489\n0.354\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nOther supported multiple estimation syntax include sw0(), csw() and csw0(). While sw() adds variables in a “stepwise” fashion, csw() does so cumulatively.\n\nfit = pf.feols(\"Y ~ X1 + X2 | csw(f1, f2)\", data)\npf.etable(fit)\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n\n\n\n\ncoef\n\n\nX1\n-0.950***\n(0.067)\n-0.924***\n(0.061)\n\n\nX2\n-0.174***\n(0.018)\n-0.174***\n(0.015)\n\n\nfe\n\n\nf2\n-\nx\n\n\nf1\nx\nx\n\n\nstats\n\n\nObservations\n997\n997\n\n\nS.E. type\nby: f1\nby: f1\n\n\nR2\n0.489\n0.659\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nThe sw0() and csw0() syntax are similar to sw() and csw(), but start with a model that excludes the variables specified in sw() and csw():\n\nfit = pf.feols(\"Y ~ X1 + X2 | sw0(f1, f2)\", data)\npf.etable(fit)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n(3)\n\n\n\n\ncoef\n\n\nX1\n-0.993***\n(0.082)\n-0.950***\n(0.067)\n-0.979***\n(0.077)\n\n\nX2\n-0.176***\n(0.022)\n-0.174***\n(0.018)\n-0.175***\n(0.022)\n\n\nIntercept\n0.889***\n(0.108)\n\n\n\n\nfe\n\n\nf2\n-\n-\nx\n\n\nf1\n-\nx\n-\n\n\nstats\n\n\nObservations\n998\n997\n998\n\n\nS.E. type\niid\nby: f1\nby: f2\n\n\nR2\n0.177\n0.489\n0.354\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nThe feols() function also supports multiple dependent variables. The following example estimates two models, one with Y1 as the dependent variable and one with Y2 as the dependent variable.\n\nfit = pf.feols(\"Y + Y2 ~ X1 | f1 + f2\", data)\npf.etable(fit)\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\nY2\n\n\n(1)\n(2)\n\n\n\n\ncoef\n\n\nX1\n-0.919***\n(0.065)\n-1.228***\n(0.195)\n\n\nfe\n\n\nf2\nx\nx\n\n\nf1\nx\nx\n\n\nstats\n\n\nObservations\n997\n998\n\n\nS.E. type\nby: f1\nby: f1\n\n\nR2\n0.609\n0.168\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nIt is possible to combine different multiple estimation operators:\n\nfit = pf.feols(\"Y + Y2 ~ X1 | sw(f1, f2)\", data)\npf.etable(fit)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\nY2\nY\nY2\n\n\n(1)\n(2)\n(3)\n(4)\n\n\n\n\ncoef\n\n\nX1\n-0.949***\n(0.069)\n-1.266***\n(0.176)\n-0.982***\n(0.081)\n-1.301***\n(0.205)\n\n\nfe\n\n\nf2\n-\n-\nx\nx\n\n\nf1\nx\nx\n-\n-\n\n\nstats\n\n\nObservations\n997\n998\n998\n999\n\n\nS.E. type\nby: f1\nby: f1\nby: f2\nby: f2\n\n\nR2\n0.437\n0.115\n0.302\n0.090\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nIn general, using muliple estimation syntax can improve the estimation time as covariates that are demeaned in one model and are used in another model do not need to be demeaned again: feols() implements a caching mechanism that stores the demeaned covariates.\nAdditionally, you can fit models on different samples via the split and fsplit arguments. The split argument splits the sample according to the variable specified in the argument, while the fsplit argument also includes the full sample in the estimation.\n\nfit = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data, split = \"f1\")\npf.etable(fit)\n\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\utils\\utils.py:162: RuntimeWarning: divide by zero encountered in scalar divide\n  cluster_adj_value = G / (G - 1)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n(8)\n(9)\n(10)\n(11)\n(12)\n(13)\n(14)\n(15)\n(16)\n(17)\n(18)\n(19)\n(20)\n(21)\n(22)\n(23)\n(24)\n(25)\n(26)\n(27)\n(28)\n(29)\n(30)\n\n\n\n\ncoef\n\n\nX1\n-1.357\n(INF)\n-1.137\n(INF)\n-0.455\n(INF)\n-1.138\n(INF)\n0.201\n(INF)\n-0.306\n(INF)\n-0.597\n(INF)\n-0.824\n(INF)\n-1.482\n(INF)\n-1.117\n(INF)\n-1.142\n(INF)\n-1.334\n(INF)\n-3.531\n(INF)\n-1.102\n(INF)\n-0.826\n(INF)\n-0.773\n(INF)\n-1.501\n(INF)\n-1.226\n(INF)\n-0.641\n(INF)\n-0.378\n(INF)\n-0.652\n(INF)\n-1.508\n(INF)\n-0.941\n(INF)\n-0.206\n(INF)\n-0.195\n(INF)\n-0.702\n(INF)\n-1.141\n(INF)\n-1.349\n(INF)\n-0.537\n(INF)\n-1.141\n(INF)\n\n\nX2\n-0.250\n(INF)\n0.198\n(INF)\n-0.145\n(INF)\n-0.330\n(INF)\n-0.177\n(INF)\n-0.187\n(INF)\n-0.118\n(INF)\n-0.292\n(INF)\n-0.029\n(INF)\n-0.264\n(INF)\n-0.148\n(INF)\n-0.313\n(INF)\n-0.152\n(INF)\n-0.296\n(INF)\n0.130\n(INF)\n-0.059\n(INF)\n-0.223\n(INF)\n-0.113\n(INF)\n-0.261\n(INF)\n0.089\n(INF)\n-0.148\n(INF)\n-0.267\n(INF)\n-0.125\n(INF)\n-0.282\n(INF)\n-0.153\n(INF)\n0.004\n(INF)\n0.083\n(INF)\n-0.226\n(INF)\n-0.158\n(INF)\n-0.160\n(INF)\n\n\nfe\n\n\nf2\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\nf1\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\nstats\n\n\nObservations\n30\n29\n44\n30\n31\n36\n36\n30\n36\n35\n32\n30\n23\n28\n34\n34\n48\n40\n36\n34\n35\n37\n27\n35\n29\n27\n43\n36\n24\n28\n\n\nS.E. type\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\nby: f1\n\n\nR2\n0.850\n0.691\n0.578\n0.745\n0.939\n0.644\n0.792\n0.776\n0.919\n0.797\n0.727\n0.822\n0.924\n0.865\n0.711\n0.808\n0.651\n0.819\n0.746\n0.731\n0.880\n0.868\n0.796\n0.648\n0.915\n0.820\n0.837\n0.789\n0.688\n0.883\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nBesides OLS, feols() also supports IV estimation via three part formulas:\n\nfit = pf.feols(\"Y ~  X2 | f1 + f2 | X1 ~ Z1\", data)\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n-1.050097\n0.085493\n-12.282912\n5.133671e-13\n-1.224949\n-0.875245\n\n\nX2\n-0.174351\n0.014779\n-11.797039\n1.369793e-12\n-0.204578\n-0.144124\n\n\n\n\n\n\n\nHere, X1 is the endogenous variable and Z1 is the instrument. f1 and f2 are the fixed effects, as before. To estimate IV models without fixed effects, simply omit the fixed effects part of the formula:\n\nfit = pf.feols(\"Y ~  X2 | X1 ~ Z1\", data)\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nIntercept\n0.861939\n0.151187\n5.701137\n1.567858e-08\n0.565257\n1.158622\n\n\nX1\n-0.967238\n0.130078\n-7.435847\n2.238210e-13\n-1.222497\n-0.711980\n\n\nX2\n-0.176416\n0.021769\n-8.104001\n1.554312e-15\n-0.219134\n-0.133697\n\n\n\n\n\n\n\nLast, feols() supports interaction of variables via the i() syntax. Documentation on this is tba.\nYou can pass custom transforms via the context argument. If you set context = 0, all functions from the level of the call to feols() will be available:\n\ndef _lspline(series: pd.Series, knots: list[float]) -&gt; np.array:\n    'Generate a linear spline design matrix for the input series based on knots.'\n    vector = series.values\n    columns = []\n\n    for i, knot in enumerate(knots):\n        column = np.minimum(vector, knot if i == 0 else knot - knots[i - 1])\n        columns.append(column)\n        vector = vector - column\n\n    # Add the remainder as the last column\n    columns.append(vector)\n\n    # Combine columns into a design matrix\n    return np.column_stack(columns)\n\nspline_split = _lspline(data[\"X2\"], [0, 1])\ndata[\"X2_0\"] = spline_split[:, 0]\ndata[\"0_X2_1\"] = spline_split[:, 1]\ndata[\"1_X2\"] = spline_split[:, 2]\n\nexplicit_fit = pf.feols(\"Y ~ X2_0 + 0_X2_1 + 1_X2 | f1 + f2\", data=data)\n# set context = 0 to make _lspline available for feols' internal call to Formulaic.model_matrix\ncontext_captured_fit = pf.feols(\"Y ~ _lspline(X2,[0,1]) | f1 + f2\", data=data, context = 0)\n# or provide it as a dict / mapping\ncontext_captured_fit_map = pf.feols(\"Y ~ _lspline(X2,[0,1]) | f1 + f2\", data=data, context = {\"_lspline\":_lspline})\n\npf.etable([explicit_fit, context_captured_fit, context_captured_fit_map])\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n(3)\n\n\n\n\ncoef\n\n\nX2_0\n-0.177***\n(0.040)\n\n\n\n\n0_X2_1\n-0.240\n(0.136)\n\n\n\n\n1_X2\n-0.140**\n(0.049)\n\n\n\n\n_lspline(X2, [0, 1])[0]\n\n-0.177***\n(0.040)\n-0.177***\n(0.040)\n\n\n_lspline(X2, [0, 1])[1]\n\n-0.240\n(0.136)\n-0.240\n(0.136)\n\n\n_lspline(X2, [0, 1])[2]\n\n-0.140**\n(0.049)\n-0.140**\n(0.049)\n\n\nfe\n\n\nf2\nx\nx\nx\n\n\nf1\nx\nx\nx\n\n\nstats\n\n\nObservations\n998\n998\n998\n\n\nS.E. type\nby: f1\nby: f1\nby: f1\n\n\nR2\n0.560\n0.560\n0.560\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nAfter fitting a model via feols(), you can use the predict() method to get the predicted values:\n\nfit = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data)\nfit.predict()[0:5]\n\narray([ 3.0633663 , -0.69574133, -0.91240433, -0.46370257, -1.67331154])\n\n\nThe predict() method also supports a newdata argument to predict on new data, which returns a numpy array of the predicted values:\n\nfit = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data)\nfit.predict(newdata=data)[0:5]\n\narray([ 2.14598761,         nan,         nan,  3.06336415, -0.69574276])\n\n\nLast, you can plot the results of a model via the coefplot() method:\n\nfit = pf.feols(\"Y ~ X1 + X2 | f1 + f2\", data)\nfit.coefplot()\n\n   \n   \n\n\nWe can conduct a regression decomposition via the decompose() method, which implements a regression decomposition following the method developed in Gelbach (2016):\n\nimport re\nimport pyfixest as pf\nfrom pyfixest.utils.dgps import gelbach_data\n\ndata_gelbach = gelbach_data(nobs = 1000)\nfit = pf.feols(\"y ~ x1 + x21 + x22 + x23\", data=data_gelbach)\n\n# simple decomposition\nres = fit.decompose(param = \"x1\")\npf.make_table(res)\n\n# group covariates via \"combine_covariates\" argument\nres = fit.decompose(param = \"x1\", combine_covariates={\"g1\": [\"x21\", \"x22\"], \"g2\": [\"x23\"]})\npf.make_table(res)\n\n# group covariates via regex\nres = fit.decompose(param=\"x1\", combine_covariates={\"g1\": re.compile(\"x2[1-2]\"), \"g2\": re.compile(\"x23\")})\n\n  0%|          | 0/1000 [00:00&lt;?, ?it/s]  1%|          | 8/1000 [00:00&lt;00:29, 33.60it/s]  2%|▏         | 16/1000 [00:07&lt;09:25,  1.74it/s]  2%|▏         | 24/1000 [00:08&lt;05:14,  3.11it/s]  7%|▋         | 72/1000 [00:08&lt;01:02, 14.81it/s] 22%|██▏       | 216/1000 [00:08&lt;00:12, 62.46it/s] 54%|█████▎    | 536/1000 [00:08&lt;00:02, 198.31it/s]100%|██████████| 1000/1000 [00:08&lt;00:00, 116.57it/s]\n  0%|          | 0/1000 [00:00&lt;?, ?it/s] 11%|█         | 112/1000 [00:00&lt;00:01, 869.67it/s] 37%|███▋      | 368/1000 [00:00&lt;00:00, 1403.89it/s] 51%|█████     | 506/1000 [00:00&lt;00:00, 1309.70it/s] 75%|███████▌  | 752/1000 [00:00&lt;00:00, 1590.94it/s]100%|██████████| 1000/1000 [00:00&lt;00:00, 1931.73it/s]\n  0%|          | 0/1000 [00:00&lt;?, ?it/s] 11%|█         | 112/1000 [00:00&lt;00:00, 1096.52it/s] 37%|███▋      | 368/1000 [00:00&lt;00:00, 1501.42it/s] 51%|█████▏    | 513/1000 [00:00&lt;00:00, 1395.57it/s] 75%|███████▌  | 752/1000 [00:00&lt;00:00, 1599.86it/s]100%|██████████| 1000/1000 [00:00&lt;00:00, 2003.19it/s]\n\n\nObjects of type Feols support a range of other methods to conduct inference. For example, you can run a wild (cluster) bootstrap via the wildboottest() method:\n\nfit = pf.feols(\"Y ~ X1 + X2\", data)\nfit.wildboottest(param = \"X1\", reps=1000)\n\nparam                    X1\nt value          -12.444998\nPr(&gt;|t|)                0.0\nbootstrap_type           11\ninference                HC\nimpose_null            True\nssc                 1.00201\ndtype: object\n\n\nwould run a wild bootstrap test for the coefficient of X1 with 1000 bootstrap repetitions.\nFor a wild cluster bootstrap, you can specify the cluster variable via the cluster argument:\n\nfit.wildboottest(param = \"X1\", reps=1000, cluster=\"group_id\")\n\nparam                             X1\nt value           -9.502246183519802\nPr(&gt;|t|)                         0.0\nbootstrap_type                    11\ninference              CRV(group_id)\nimpose_null                     True\nssc                         1.057677\ndtype: object\n\n\nThe ritest() method can be used to conduct randomization inference:\n\nfit.ritest(resampvar = \"X1\", reps=1000)\n\nH0                                      X1=0\nri-type                      randomization-c\nEstimate                 -0.9929357698186859\nPr(&gt;|t|)                                 0.0\nStd. Error (Pr(&gt;|t|))                    0.0\n2.5% (Pr(&gt;|t|))                          0.0\n97.5% (Pr(&gt;|t|))                         0.0\ndtype: object\n\n\nLast, you can compute the cluster causal variance estimator by Athey et al by using the ccv() method:\n\nimport numpy as np\nrng = np.random.default_rng(1234)\ndata[\"D\"] = rng.choice([0, 1], size = data.shape[0])\nfit_D = pf.feols(\"Y ~ D\", data = data)\nfit_D.ccv(treatment = \"D\", cluster = \"group_id\")\n\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\estimation\\feols_.py:1383: UserWarning: The initial model was not clustered. CRV1 inference is computed and stored in the model object.\n  warnings.warn(\n\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\n\n\nCCV\n0.016087657906364183\n0.228337\n0.070456\n0.944608\n-0.463631\n0.495807\n\n\nCRV1\n0.016088\n0.13378\n0.120254\n0.905614\n-0.264974\n0.29715",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.feols"
    ]
  },
  {
    "objectID": "reference/estimation.detect_singletons.html",
    "href": "reference/estimation.detect_singletons.html",
    "title": "estimation.detect_singletons",
    "section": "",
    "text": "estimation.detect_singletons(ids)\nDetect singleton fixed effects in a dataset.\nThis function iterates over the columns of a 2D numpy array representing fixed effects to identify singleton fixed effects. An observation is considered a singleton if it is the only one in its group (fixed effect identifier).\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nids\nnp.ndarray\nA 2D numpy array representing fixed effects, with a shape of (n_samples, n_features). Elements should be non-negative integers representing fixed effect identifiers.\nrequired\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnumpy.ndarray\nA boolean array of shape (n_samples,), indicating which observations have a singleton fixed effect.\n\n\n\n\n\n\nThe algorithm iterates over columns to identify fixed effects. After each column is processed, it updates the record of non-singleton rows. This approach accounts for the possibility that removing an observation in one column can lead to the emergence of new singletons in subsequent columns.\nFor performance reasons, the input array should be in column-major order. Operating on a row-major array can lead to significant performance losses.",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.detect_singletons"
    ]
  },
  {
    "objectID": "reference/estimation.detect_singletons.html#parameters",
    "href": "reference/estimation.detect_singletons.html#parameters",
    "title": "estimation.detect_singletons",
    "section": "",
    "text": "Name\nType\nDescription\nDefault\n\n\n\n\nids\nnp.ndarray\nA 2D numpy array representing fixed effects, with a shape of (n_samples, n_features). Elements should be non-negative integers representing fixed effect identifiers.\nrequired",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.detect_singletons"
    ]
  },
  {
    "objectID": "reference/estimation.detect_singletons.html#returns",
    "href": "reference/estimation.detect_singletons.html#returns",
    "title": "estimation.detect_singletons",
    "section": "",
    "text": "Name\nType\nDescription\n\n\n\n\n\nnumpy.ndarray\nA boolean array of shape (n_samples,), indicating which observations have a singleton fixed effect.",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.detect_singletons"
    ]
  },
  {
    "objectID": "reference/estimation.detect_singletons.html#notes",
    "href": "reference/estimation.detect_singletons.html#notes",
    "title": "estimation.detect_singletons",
    "section": "",
    "text": "The algorithm iterates over columns to identify fixed effects. After each column is processed, it updates the record of non-singleton rows. This approach accounts for the possibility that removing an observation in one column can lead to the emergence of new singletons in subsequent columns.\nFor performance reasons, the input array should be in column-major order. Operating on a row-major array can lead to significant performance losses.",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.detect_singletons"
    ]
  },
  {
    "objectID": "reference/estimation.bonferroni.html",
    "href": "reference/estimation.bonferroni.html",
    "title": "estimation.bonferroni",
    "section": "",
    "text": "estimation.bonferroni(models, param)\nCompute Bonferroni adjusted p-values for multiple hypothesis testing.\nFor each model, it is assumed that tests to adjust are of the form “param = 0”.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.bonferroni"
    ]
  },
  {
    "objectID": "reference/estimation.bonferroni.html#parameters",
    "href": "reference/estimation.bonferroni.html#parameters",
    "title": "estimation.bonferroni",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodels\nA supported model object (Feols, Fepois, Feiv, FixestMulti) or a list of\nFeols, Fepois & Feiv models.\nrequired\n\n\nparam\nstr\nThe parameter for which the p-values should be adjusted.\nrequired",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.bonferroni"
    ]
  },
  {
    "objectID": "reference/estimation.bonferroni.html#returns",
    "href": "reference/estimation.bonferroni.html#returns",
    "title": "estimation.bonferroni",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.DataFrame\nA DataFrame containing estimation statistics, including the Bonferroni adjusted p-values.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.bonferroni"
    ]
  },
  {
    "objectID": "reference/estimation.bonferroni.html#examples",
    "href": "reference/estimation.bonferroni.html#examples",
    "title": "estimation.bonferroni",
    "section": "Examples",
    "text": "Examples\n\nimport pyfixest as pf\nfrom pyfixest.utils import get_data\n\ndata = get_data().dropna()\nfit1 = pf.feols(\"Y ~ X1\", data=data)\nfit2 = pf.feols(\"Y ~ X1 + X2\", data=data)\nbonf_df = pf.bonferroni([fit1, fit2], param=\"X1\")\nbonf_df\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nest0\nest1\n\n\n\n\nEstimate\n-1.001930\n-0.995197\n\n\nStd. Error\n0.084823\n0.082194\n\n\nt value\n-11.811964\n-12.107957\n\n\nPr(&gt;|t|)\n0.000000\n0.000000\n\n\n2.5%\n-1.168383\n-1.156490\n\n\n97.5%\n-0.835476\n-0.833904\n\n\nBonferroni Pr(&gt;|t|)\n0.000000\n0.000000",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.bonferroni"
    ]
  },
  {
    "objectID": "reference/did.estimation.lpdid.html",
    "href": "reference/did.estimation.lpdid.html",
    "title": "did.estimation.lpdid",
    "section": "",
    "text": "did.estimation.lpdid(\n    data,\n    yname,\n    idname,\n    tname,\n    gname,\n    vcov=None,\n    pre_window=None,\n    post_window=None,\n    never_treated=0,\n    att=True,\n    xfml=None,\n)\nLocal projections approach to estimation.\nEstimate a Difference-in-Differences / Event Study Model via the Local Projections Approach.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.lpdid"
    ]
  },
  {
    "objectID": "reference/did.estimation.lpdid.html#parameters",
    "href": "reference/did.estimation.lpdid.html#parameters",
    "title": "did.estimation.lpdid",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ndata\nDataFrame\nThe DataFrame containing all variables.\nrequired\n\n\nyname\nstr\nThe name of the dependent variable.\nrequired\n\n\nidname\nstr\nThe name of the id variable.\nrequired\n\n\ntname\nstr\nVariable name for calendar period.\nrequired\n\n\ngname\nstr\nUnit-specific time of initial treatment.\nrequired\n\n\nvcov\n(str, dict)\nThe type of inference to employ. Defaults to {“CRV1”: idname}. Options include “iid”, “hetero”, or a dictionary like {“CRV1”: idname}.\nNone\n\n\npre_window\nint\nThe number of periods before the treatment to include in the estimation. Default is the minimum relative year in the data.\nNone\n\n\npost_window\nint\nThe number of periods after the treatment to include in the estimation. Default is the maximum relative year in the data.\nNone\n\n\nnever_treated\nint\nValue in gname indicating units never treated. Default is 0.\n0\n\n\natt\nbool\nIf True, estimates the pooled average treatment effect on the treated (ATT). Default is False.\nTrue\n\n\nxfml\nstr\nFormula for the covariates. Not yet supported.\nNone",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.lpdid"
    ]
  },
  {
    "objectID": "reference/did.estimation.lpdid.html#returns",
    "href": "reference/did.estimation.lpdid.html#returns",
    "title": "did.estimation.lpdid",
    "section": "Returns",
    "text": "Returns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nDataFrame\nA DataFrame with the estimated coefficients.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.lpdid"
    ]
  },
  {
    "objectID": "reference/did.estimation.lpdid.html#examples",
    "href": "reference/did.estimation.lpdid.html#examples",
    "title": "did.estimation.lpdid",
    "section": "Examples",
    "text": "Examples\n\nimport pandas as pd\nimport pyfixest as pf\n\nurl = \"https://raw.githubusercontent.com/py-econometrics/pyfixest/master/pyfixest/did/data/df_het.csv\"\ndf_het = pd.read_csv(url)\n\nfit = pf.lpdid(\n    df_het,\n    yname=\"dep_var\",\n    idname=\"unit\",\n    tname=\"year\",\n    gname=\"g\",\n    vcov={\"CRV1\": \"state\"},\n    pre_window=-20,\n    post_window=20,\n    att=False\n)\n\nfit.tidy().head()\nfit.iplot(figsize= [1200, 400], coord_flip=False).show()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n   \n   \n\n\nTo get the ATT, set att=True:\n\nfit = pf.lpdid(\n    df_het,\n    yname=\"dep_var\",\n    idname=\"unit\",\n    tname=\"year\",\n    gname=\"g\",\n    vcov={\"CRV1\": \"state\"},\n    pre_window=-20,\n    post_window=20,\n    att=True\n)\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\nN\n\n\n\n\ntreat_diff\n2.506746\n0.071357\n35.129648\n0.0\n2.362413\n2.65108\n5716.0",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.lpdid"
    ]
  },
  {
    "objectID": "reference/did.estimation.did2s.html",
    "href": "reference/did.estimation.did2s.html",
    "title": "did.estimation.did2s",
    "section": "",
    "text": "did.estimation.did2s(\n    data,\n    yname,\n    first_stage,\n    second_stage,\n    treatment,\n    cluster,\n    weights=None,\n)\nEstimate a Difference-in-Differences model using Gardner’s two-step DID2S estimator.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.did2s"
    ]
  },
  {
    "objectID": "reference/did.estimation.did2s.html#parameters",
    "href": "reference/did.estimation.did2s.html#parameters",
    "title": "did.estimation.did2s",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ndata\npd.DataFrame\nThe DataFrame containing all variables.\nrequired\n\n\nyname\nstr\nThe name of the dependent variable.\nrequired\n\n\nfirst_stage\nstr\nThe formula for the first stage, starting with ‘~’.\nrequired\n\n\nsecond_stage\nstr\nThe formula for the second stage, starting with ‘~’.\nrequired\n\n\ntreatment\nstr\nThe name of the treatment variable.\nrequired\n\n\ncluster\nstr\nThe name of the cluster variable.\nrequired",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.did2s"
    ]
  },
  {
    "objectID": "reference/did.estimation.did2s.html#returns",
    "href": "reference/did.estimation.did2s.html#returns",
    "title": "did.estimation.did2s",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nobject\nA fitted model object of class [Feols(/reference/Feols.qmd).",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.did2s"
    ]
  },
  {
    "objectID": "reference/did.estimation.did2s.html#examples",
    "href": "reference/did.estimation.did2s.html#examples",
    "title": "did.estimation.did2s",
    "section": "Examples",
    "text": "Examples\n\nimport pandas as pd\nimport numpy as np\nimport pyfixest as pf\n\nurl = \"https://raw.githubusercontent.com/py-econometrics/pyfixest/master/pyfixest/did/data/df_het.csv\"\ndf_het = pd.read_csv(url)\ndf_het.head()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nunit\nstate\ngroup\nunit_fe\ng\nyear\nyear_fe\ntreat\nrel_year\nrel_year_binned\nerror\nte\nte_dynamic\ndep_var\n\n\n\n\n0\n1\n33\nGroup 2\n7.043016\n2010\n1990\n0.066159\nFalse\n-20.0\n-6\n-0.086466\n0\n0.0\n7.022709\n\n\n1\n1\n33\nGroup 2\n7.043016\n2010\n1991\n-0.030980\nFalse\n-19.0\n-6\n0.766593\n0\n0.0\n7.778628\n\n\n2\n1\n33\nGroup 2\n7.043016\n2010\n1992\n-0.119607\nFalse\n-18.0\n-6\n1.512968\n0\n0.0\n8.436377\n\n\n3\n1\n33\nGroup 2\n7.043016\n2010\n1993\n0.126321\nFalse\n-17.0\n-6\n0.021870\n0\n0.0\n7.191207\n\n\n4\n1\n33\nGroup 2\n7.043016\n2010\n1994\n-0.106921\nFalse\n-16.0\n-6\n-0.017603\n0\n0.0\n6.918492\n\n\n\n\n\n\n\nIn a first step, we estimate a classical event study model:\n\n# estimate the model\nfit = pf.did2s(\n    df_het,\n    yname=\"dep_var\",\n    first_stage=\"~ 0 | unit + year\",\n    second_stage=\"~i(rel_year, ref=-1.0)\",\n    treatment=\"treat\",\n    cluster=\"state\",\n)\n\nfit.tidy().head()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nC(rel_year, contr.treatment(base=-1.0))[T.-inf]\n1.905043e-09\n3.134439e-10\n6.077778\n4.038252e-07\n1.271042e-09\n2.539043e-09\n\n\nC(rel_year, contr.treatment(base=-1.0))[T.-20.0]\n-5.822583e-02\n3.580900e-02\n-1.626011\n1.120020e-01\n-1.306564e-01\n1.420471e-02\n\n\nC(rel_year, contr.treatment(base=-1.0))[T.-19.0]\n-6.032229e-03\n3.034072e-02\n-0.198816\n8.434394e-01\n-6.740213e-02\n5.533768e-02\n\n\nC(rel_year, contr.treatment(base=-1.0))[T.-18.0]\n-6.152383e-03\n3.509400e-02\n-0.175312\n8.617419e-01\n-7.713670e-02\n6.483193e-02\n\n\nC(rel_year, contr.treatment(base=-1.0))[T.-17.0]\n-1.253330e-02\n2.483369e-02\n-0.504690\n6.166168e-01\n-6.276418e-02\n3.769757e-02\n\n\n\n\n\n\n\nWe can also inspect the model visually:\n\nfit.iplot(figsize= [1200, 400], coord_flip=False).show()\n\n   \n   \n\n\nTo estimate a pooled effect, we need to slightly update the second stage formula:\n\nfit = pf.did2s(\n    df_het,\n    yname=\"dep_var\",\n    first_stage=\"~ 0 | unit + year\",\n    second_stage=\"~i(treat)\",\n    treatment=\"treat\",\n    cluster=\"state\"\n)\nfit.tidy().head()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nC(treat)[T.True]\n2.230482\n0.024709\n90.271437\n0.0\n2.180504\n2.28046",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.did2s"
    ]
  },
  {
    "objectID": "multiple_testing.html",
    "href": "multiple_testing.html",
    "title": "Multiple Hypothesis Testing Corrections",
    "section": "",
    "text": "When conducting online A/B tests or large-scale experiments, we often analyze multiple dependent variables simultaneously. Analyzing multiple KPIs introduces a significant statistical challenge: the multiple testing problem.\nIn classical hypothesis testing, the significance level \\(\\alpha\\) controls the probability of a false positive (Type I error), typically \\(\\alpha=0.05\\). While this ensures a 5% chance of a false positive for a single test, the likelihood of detecting at least one false positive grows rapidly when conducting multiple tests. For example, testing 20 KPIs independently at \\(\\alpha = 0.05\\) results in a 64% chance of at least one false positive—calculated as \\(1 - (1 - 0.05)^{20} \\approx 0.64\\). This issue, known as the multiple testing problem, can lead to false claims of significant effects when none exist.\nTo address this, the concept of controlling the Familywise Error Rate (FWER) has been widely adopted. FWER controls the probability of at least one Type I error across a family of hypotheses. Several correction methods exist to mitigate the multiple testing problem, including:\nThis vignette demonstrates how these methods effectively control the FWER in a variety of scenarios. We will compare their performance and highlight the trade-offs between simplicity and statistical power. Specifically, we show that while Bonferroni provides strong error control, it is conservative in many practical applications. In contrast, Romano-Wolf and Westfall-Young methods are more powerful, offering greater sensitivity to detect true effects while maintaining robust control of the FWER."
  },
  {
    "objectID": "multiple_testing.html#what-is-a-family-wise-error-rate-fwer",
    "href": "multiple_testing.html#what-is-a-family-wise-error-rate-fwer",
    "title": "Multiple Hypothesis Testing Corrections",
    "section": "What is a Family-Wise Error Rate (FWER)?",
    "text": "What is a Family-Wise Error Rate (FWER)?\nSuppose that we are running an experiment and want to test if our treatment impacts 20 different dependent variables (KPIs). For any given independent test, the chance of a false positive is given by the (significance) level of the individual test, which is most commonly set to \\(\\alpha = 0.05\\). Formally, we can define the false positive rate for a single hypothesis \\(H\\) as:\n\\[\nP(\\text{reject } H \\mid H \\text{ is true}) = \\alpha\n\\]\nFor a family of tests \\(S = {s \\in \\{1, \\dots, P\\} }\\) hypotheses \\(\\{H_{s}\\}_{s \\in S}\\), we can analogously define the family-wise error rate (FWER) as:\n\\[\nP(\\text{reject at least one } H_{s} \\text{ with } s \\in I) = \\alpha\n\\]\nwhere \\(I\\) is the set of true hypotheses. In other words, the FWER is the probability of making at least one false positive across all tests in the family."
  },
  {
    "objectID": "multiple_testing.html#setup",
    "href": "multiple_testing.html#setup",
    "title": "Multiple Hypothesis Testing Corrections",
    "section": "Setup",
    "text": "Setup\nIn a first step, we create a data set with multiple (potentially correlated) dependent variables that share a common set of covariates. All simulations in this notebook are greatly inspired by Clarke, Romano & Wolf (Stata Journal, 2020).\n\n%load_ext autoreload\n%autoreload 2\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom great_tables import loc, style\nfrom joblib import Parallel, delayed\nfrom tqdm import tqdm\n\nimport pyfixest as pf\n\nThe autoreload extension is already loaded. To reload it, use:\n  %reload_ext autoreload\n\n\n\nN = 100\nn_covariates = 5\nn_depvars = 20\n\n\ndef get_data(N, n_covariates, n_depvars, rho, seed):\n    \"Simulate data with true nulls.\"\n    rng = np.random.default_rng(seed)\n    Omega = np.eye(n_depvars)\n    X = rng.standard_normal((N, n_covariates))\n    u_joint = np.random.multivariate_normal(np.zeros(n_depvars), Omega, N)\n    beta = np.zeros((n_covariates, n_depvars))\n    y = X @ beta + u_joint\n\n    data = pd.DataFrame(X, columns=[f\"X{i}\" for i in range(n_covariates)])\n    data = data.assign(**{f\"y{i}\": y[:, i] for i in range(n_depvars)})\n\n    return data\n\n\ndata = get_data(\n    N=N, n_covariates=n_covariates, n_depvars=n_depvars, rho=0.5, seed=12345\n)\ndata.head()\n\n\n\n\n\n\n\n\nX0\nX1\nX2\nX3\nX4\ny0\ny1\ny2\ny3\ny4\n...\ny10\ny11\ny12\ny13\ny14\ny15\ny16\ny17\ny18\ny19\n\n\n\n\n0\n-1.423825\n1.263728\n-0.870662\n-0.259173\n-0.075343\n0.285444\n-0.613527\n1.064762\n0.941035\n-0.188382\n...\n0.947734\n0.505579\n-2.838629\n-0.563997\n1.757725\n-0.187876\n2.554182\n-2.486495\n0.216818\n0.298878\n\n\n1\n-0.740885\n-1.367793\n0.648893\n0.361058\n-1.952863\n1.365574\n0.404626\n-1.869440\n-0.008121\n2.129185\n...\n0.439416\n-1.992477\n-0.002794\n1.603059\n-0.244048\n0.880147\n0.700935\n-0.375832\n1.113939\n0.279370\n\n\n2\n2.347410\n0.968497\n-0.759387\n0.902198\n-0.466953\n0.215444\n-0.282206\n0.720051\n0.366021\n1.051319\n...\n0.272646\n-0.507247\n-0.784782\n-1.007066\n0.840372\n-1.150062\n2.082881\n0.583346\n1.077486\n0.027789\n\n\n3\n-0.060690\n0.788844\n-1.256668\n0.575858\n1.398979\n-1.065016\n1.185823\n0.970361\n-0.765870\n0.479013\n...\n-1.007019\n0.924188\n1.949084\n-1.560250\n1.167244\n-0.837087\n0.360323\n0.640585\n0.527408\n-0.033194\n\n\n4\n1.322298\n-0.299699\n0.902919\n-1.621583\n-0.158189\n0.664518\n1.456532\n1.858938\n-0.285083\n-0.379121\n...\n-0.960765\n-0.238118\n-1.055520\n-0.486306\n0.583903\n0.718977\n-0.122756\n0.545447\n0.174667\n0.926524\n\n\n\n\n5 rows × 25 columns\n\n\n\nNow that we have our data set at hand, we can fit 20 regression models - one for each dependent variable. To do so, we will use pyfixest’s multiple estimation syntax.\n\ndependent_vars = \" + \".join([f\"y{i}\" for i in range(20)])\nindependent_vars = \" + \".join([f\"X{i}\" for i in range(5)])\nfml = f\"{dependent_vars} ~ {independent_vars}\"\n\n\nfit = pf.feols(fml, data=data, vcov=\"hetero\")\n\n\n(pf.etable(fit).tab_style(style=style.fill(color=\"yellow\"), locations=loc.body(rows=1)))\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ny0\ny1\ny2\ny3\ny4\ny5\ny6\ny7\ny8\ny9\ny10\ny11\ny12\ny13\ny14\ny15\ny16\ny17\ny18\ny19\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n(8)\n(9)\n(10)\n(11)\n(12)\n(13)\n(14)\n(15)\n(16)\n(17)\n(18)\n(19)\n(20)\n\n\n\n\ncoef\n\n\nX0\n0.079\n(0.119)\n0.111\n(0.108)\n0.088\n(0.105)\n0.158\n(0.094)\n0.033\n(0.112)\n-0.011\n(0.100)\n-0.223*\n(0.100)\n0.020\n(0.117)\n-0.172*\n(0.083)\n0.068\n(0.082)\n0.009\n(0.114)\n0.023\n(0.106)\n0.002\n(0.099)\n0.100\n(0.092)\n-0.068\n(0.098)\n-0.022\n(0.100)\n0.153\n(0.123)\n0.231*\n(0.095)\n0.113\n(0.120)\n-0.051\n(0.079)\n\n\nX1\n-0.064\n(0.093)\n-0.065\n(0.108)\n-0.055\n(0.107)\n-0.055\n(0.097)\n-0.013\n(0.101)\n0.036\n(0.092)\n-0.038\n(0.100)\n-0.052\n(0.112)\n0.080\n(0.084)\n0.072\n(0.088)\n0.002\n(0.092)\n0.049\n(0.124)\n-0.017\n(0.102)\n0.061\n(0.099)\n-0.023\n(0.086)\n-0.017\n(0.090)\n0.159\n(0.113)\n0.032\n(0.122)\n-0.144\n(0.100)\n0.064\n(0.088)\n\n\nX2\n-0.165\n(0.116)\n-0.181\n(0.125)\n0.107\n(0.090)\n-0.027\n(0.094)\n-0.080\n(0.111)\n0.009\n(0.079)\n0.185\n(0.098)\n-0.023\n(0.108)\n0.025\n(0.075)\n-0.155\n(0.086)\n-0.008\n(0.095)\n0.175\n(0.116)\n0.153\n(0.091)\n0.127\n(0.090)\n0.042\n(0.105)\n0.142\n(0.094)\n-0.081\n(0.116)\n-0.195\n(0.105)\n-0.200\n(0.107)\n0.015\n(0.095)\n\n\nX3\n-0.110\n(0.089)\n0.133\n(0.108)\n0.018\n(0.110)\n0.006\n(0.090)\n0.036\n(0.100)\n-0.083\n(0.105)\n0.202*\n(0.094)\n0.105\n(0.118)\n0.005\n(0.081)\n-0.003\n(0.113)\n0.015\n(0.115)\n0.095\n(0.093)\n0.030\n(0.103)\n0.076\n(0.112)\n-0.080\n(0.085)\n0.067\n(0.106)\n-0.057\n(0.127)\n-0.016\n(0.106)\n0.051\n(0.102)\n-0.003\n(0.088)\n\n\nX4\n0.017\n(0.114)\n0.124\n(0.128)\n0.126\n(0.107)\n-0.014\n(0.085)\n-0.120\n(0.100)\n0.067\n(0.094)\n0.118\n(0.105)\n-0.035\n(0.107)\n-0.127\n(0.075)\n0.126\n(0.094)\n0.004\n(0.101)\n0.035\n(0.120)\n0.200*\n(0.098)\n0.011\n(0.119)\n-0.222**\n(0.083)\n-0.131\n(0.095)\n-0.029\n(0.113)\n0.146\n(0.106)\n-0.104\n(0.109)\n0.018\n(0.084)\n\n\nIntercept\n0.121\n(0.101)\n0.020\n(0.115)\n0.191\n(0.108)\n0.103\n(0.086)\n-0.069\n(0.103)\n-0.090\n(0.096)\n-0.010\n(0.099)\n0.021\n(0.103)\n-0.024\n(0.082)\n-0.026\n(0.102)\n0.103\n(0.111)\n-0.130\n(0.112)\n0.132\n(0.098)\n0.004\n(0.104)\n-0.043\n(0.088)\n-0.046\n(0.100)\n0.115\n(0.111)\n-0.084\n(0.114)\n0.066\n(0.109)\n0.014\n(0.090)\n\n\nstats\n\n\nObservations\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n\n\nS.E. type\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\n\n\nR2\n0.039\n0.068\n0.037\n0.033\n0.022\n0.015\n0.144\n0.015\n0.063\n0.051\n0.000\n0.035\n0.068\n0.037\n0.079\n0.040\n0.057\n0.078\n0.069\n0.009\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe see that our estimation produces multiple false positives for the effect of X1 on multiple dependent variables. Recall that we had simulated X1 to have no effect on any of the dependent variables. Still, the estimation procedure produces a significant effect for X1 on multiple dependent variables.\nPyFixest provides three functions to adjust inference for multiple testing: pf.bonferroni(), pf.rwolf(), and pf.wyoung(). All three share a common API.\n\npval_bonferroni = (\n    pf.bonferroni(fit.to_list(), param=\"X1\").xs(\"Bonferroni Pr(&gt;|t|)\").values\n)\n\npval_rwolf = (\n    pf.rwolf(fit.to_list(), param=\"X1\", reps=1000, seed=22).xs(\"RW Pr(&gt;|t|)\").values\n)\n\npval_wyoung = (\n    pf.wyoung(fit.to_list(), param=\"X1\", reps=1000, seed=22).xs(\"WY Pr(&gt;|t|)\").values\n)\n\n\n(\n    pf.etable(\n        fit,\n        custom_model_stats={\n            \"Bonferroni: pval(X1)\": pval_bonferroni.round(4).tolist(),\n            \"RW: pval(X1)\": pval_rwolf.round(4).tolist(),\n            \"WY: pval(X1)\": pval_wyoung.round(4).tolist(),\n        },\n    ).tab_style(style=style.fill(color=\"yellow\"), locations=loc.body(rows=[6, 7, 8]))\n)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ny0\ny1\ny2\ny3\ny4\ny5\ny6\ny7\ny8\ny9\ny10\ny11\ny12\ny13\ny14\ny15\ny16\ny17\ny18\ny19\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n(8)\n(9)\n(10)\n(11)\n(12)\n(13)\n(14)\n(15)\n(16)\n(17)\n(18)\n(19)\n(20)\n\n\n\n\ncoef\n\n\nX0\n0.192\n(0.105)\n-0.125\n(0.122)\n-0.184\n(0.095)\n0.067\n(0.110)\n-0.279*\n(0.118)\n-0.064\n(0.123)\n-0.041\n(0.093)\n0.079\n(0.089)\n0.050\n(0.107)\n0.075\n(0.113)\n0.059\n(0.096)\n-0.163\n(0.094)\n0.172\n(0.110)\n0.090\n(0.122)\n0.032\n(0.104)\n0.025\n(0.106)\n0.075\n(0.092)\n0.055\n(0.126)\n-0.142\n(0.101)\n-0.027\n(0.092)\n\n\nX1\n0.053\n(0.104)\n0.030\n(0.124)\n0.162\n(0.084)\n0.024\n(0.111)\n-0.037\n(0.104)\n0.087\n(0.088)\n-0.011\n(0.089)\n-0.075\n(0.091)\n0.039\n(0.102)\n0.083\n(0.112)\n-0.060\n(0.101)\n0.139\n(0.089)\n-0.183\n(0.109)\n-0.038\n(0.117)\n-0.038\n(0.112)\n-0.191\n(0.108)\n-0.016\n(0.095)\n0.128\n(0.099)\n0.074\n(0.099)\n0.120\n(0.088)\n\n\nX2\n-0.164\n(0.095)\n0.140\n(0.112)\n0.058\n(0.103)\n-0.065\n(0.095)\n0.003\n(0.113)\n0.282**\n(0.098)\n0.077\n(0.110)\n0.081\n(0.110)\n0.125\n(0.105)\n-0.011\n(0.105)\n0.116\n(0.109)\n0.003\n(0.107)\n-0.138\n(0.109)\n-0.138\n(0.091)\n0.053\n(0.093)\n0.011\n(0.109)\n0.046\n(0.103)\n0.073\n(0.121)\n0.079\n(0.134)\n0.187\n(0.100)\n\n\nX3\n0.022\n(0.108)\n-0.041\n(0.117)\n-0.015\n(0.098)\n0.042\n(0.088)\n-0.121\n(0.096)\n-0.037\n(0.101)\n0.008\n(0.090)\n-0.108\n(0.090)\n0.039\n(0.096)\n0.115\n(0.118)\n-0.064\n(0.109)\n-0.065\n(0.098)\n0.053\n(0.100)\n0.062\n(0.121)\n-0.099\n(0.107)\n0.173\n(0.090)\n-0.036\n(0.095)\n0.147\n(0.097)\n-0.039\n(0.114)\n-0.027\n(0.093)\n\n\nX4\n-0.109\n(0.099)\n-0.071\n(0.120)\n0.026\n(0.093)\n0.064\n(0.074)\n0.062\n(0.127)\n0.021\n(0.088)\n-0.035\n(0.104)\n-0.082\n(0.085)\n0.059\n(0.093)\n0.027\n(0.092)\n0.084\n(0.105)\n-0.123\n(0.114)\n-0.142\n(0.107)\n0.105\n(0.103)\n0.004\n(0.113)\n0.002\n(0.097)\n0.040\n(0.091)\n-0.063\n(0.099)\n0.006\n(0.105)\n-0.010\n(0.092)\n\n\nIntercept\n0.169\n(0.105)\n0.094\n(0.117)\n-0.021\n(0.097)\n0.188*\n(0.090)\n-0.034\n(0.112)\n-0.047\n(0.101)\n0.048\n(0.098)\n-0.161\n(0.092)\n-0.109\n(0.101)\n-0.047\n(0.113)\n-0.227*\n(0.095)\n0.006\n(0.101)\n0.136\n(0.102)\n0.212*\n(0.097)\n-0.042\n(0.103)\n0.128\n(0.104)\n0.029\n(0.103)\n-0.139\n(0.110)\n-0.052\n(0.106)\n0.049\n(0.097)\n\n\nstats\n\n\nBonferroni: pval(X1)\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n1.0\n\n\nRW: pval(X1)\n1.0\n1.0\n0.7273\n1.0\n1.0\n0.996\n1.0\n0.998\n1.0\n0.999\n1.0\n0.8921\n0.8521\n1.0\n1.0\n0.8162\n1.0\n0.956\n0.999\n0.954\n\n\nWY: pval(X1)\n1.0\n1.0\n0.727\n1.0\n1.0\n0.996\n1.0\n0.998\n1.0\n0.999\n1.0\n0.892\n0.852\n1.0\n1.0\n0.816\n1.0\n0.956\n0.999\n0.954\n\n\nObservations\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n\n\nS.E. type\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\nhetero\n\n\nR2\n0.078\n0.030\n0.063\n0.017\n0.079\n0.085\n0.009\n0.048\n0.026\n0.023\n0.033\n0.061\n0.097\n0.040\n0.014\n0.076\n0.011\n0.035\n0.024\n0.051\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe quickly see that the corrected p-values do not flag any false positives."
  },
  {
    "objectID": "multiple_testing.html#controlling-for-the-familiy-wise-error-rate-fwer",
    "href": "multiple_testing.html#controlling-for-the-familiy-wise-error-rate-fwer",
    "title": "Multiple Hypothesis Testing Corrections",
    "section": "Controlling for the Familiy-Wise Error Rate (FWER)",
    "text": "Controlling for the Familiy-Wise Error Rate (FWER)\nWe now show by means of simulation that the three methods control the family-wise error rate (FWER). To do so, we simulate 1000 data sets imposing true nulls for the effect of X1 on all of 20 created dependent variables. For each simulation, we then count if the methods flag more than one false positive and report our results.\n\ndef compute_family_rejection(seed, rho):\n    \"Simulate data, estimate models, and compute family rejection rates.\"\n    data = get_data(N, n_covariates, n_depvars, rho, seed=seed)\n    fit = pf.feols(fml=fml, data=data, vcov=\"hetero\")\n    df = fit.tidy().reset_index().set_index(\"Coefficient\").xs(\"X1\")\n\n    df[\"Pr(&gt;|t|) reject\"] = df[\"Pr(&gt;|t|)\"] &lt; 0.05\n    df[\"Bonferroni reject\"] = (\n        pf.bonferroni(fit, param=\"X1\").xs(\"Bonferroni Pr(&gt;|t|)\").values &lt; 0.05\n    )\n    df[\"rwolf reject\"] = (\n        pf.rwolf(fit, param=\"X1\", reps=1000, seed=seed * 11).xs(\"RW Pr(&gt;|t|)\").values\n        &lt; 0.05\n    )\n    df[\"wyoung reject\"] = (\n        pf.wyoung(fit, param=\"X1\", reps=1000, seed=seed * 11).xs(\"WY Pr(&gt;|t|)\").values\n        &lt; 0.05\n    )\n\n    # Compute family rejection means\n    family_rejection = {\n        \"Pr(&gt;|t|) reject family\": df[\"Pr(&gt;|t|) reject\"].sum() &gt; 0,\n        \"Bonferroni reject family\": df[\"Bonferroni reject\"].sum() &gt; 0,\n        \"rwolf reject family\": df[\"rwolf reject\"].sum() &gt; 0,\n        \"wyoung reject family\": df[\"wyoung reject\"].sum() &gt; 0,\n    }\n\n    return pd.Series(family_rejection)\n\n\ndef run_fwer_simulation(n_iter, rho):\n    \"Run simulation for family-wise error rate.\"\n    results = Parallel(n_jobs=-1)(\n        delayed(compute_family_rejection)(seed, rho=rho) for seed in tqdm(range(n_iter))\n    )\n    return pd.concat(results).reset_index().groupby(\"index\").mean()\n\n\nrun_fwer_simulation(n_iter=1000, rho=0.5)\n\n100%|██████████| 1000/1000 [19:03&lt;00:00,  1.14s/it]\n\n\n\n\n\n\n\n\n\n0\n\n\nindex\n\n\n\n\n\nBonferroni reject family\n0.069\n\n\nPr(&gt;|t|) reject family\n0.694\n\n\nrwolf reject family\n0.043\n\n\nwyoung reject family\n0.043\n\n\n\n\n\n\n\nWe see that all three correction methods get close to the desired 5% level. In contrast, the uncorrected method produces the expected much higher family-wise error rate."
  },
  {
    "objectID": "multiple_testing.html#power",
    "href": "multiple_testing.html#power",
    "title": "Multiple Hypothesis Testing Corrections",
    "section": "Power",
    "text": "Power\nNow that we’ve seen that all three methods effectively handle false positives, let’s see how well they avoid false negatives. In other words, we will study how powerful all three methods are in detecting true effects.\nTo do so, we slightly have to adjust the data generating process. Instead of simulating the impact of X1 on all dependent variables to be zero (a true null effect), we will now simulate the impact of X1 to be \\(0.5\\) for all dependent variables. Hence we simulate true positives and count how often we correctly detect the true effect, or, equivalently stated, how often we correctly reject the null of no treatment effect.\n\ndef get_data_true_effect(N, n_covariates, n_depvars, rho=0.5, seed=12345, effect=0.1):\n    \"Generate data with true positives.\"\n    rng = np.random.default_rng(seed)\n    Omega = np.eye(n_depvars)\n    Omega[Omega != 1] = rho\n    X = rng.standard_normal((N, n_covariates))\n    u_joint = np.random.multivariate_normal(np.zeros(n_depvars), Omega, N)\n    beta = np.zeros((n_covariates, n_depvars))\n    beta[1, :] = effect\n    y = X @ beta + u_joint\n\n    data = pd.DataFrame(X, columns=[f\"X{i}\" for i in range(n_covariates)])\n    data = data.assign(**{f\"y{i}\": y[:, i] for i in range(n_depvars)})\n\n    return data\n\n\ndata_true = get_data_true_effect(\n    N=N, n_covariates=n_covariates, n_depvars=n_depvars, rho=0.5, seed=12345, effect=0.5\n)\nfit = pf.feols(fml, data=data_true)\n\n\n(\n    pf.etable(fit).tab_style(\n        style=style.fill(color=\"yellow\"), locations=loc.body(rows=[1])\n    )\n)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ny0\ny1\ny2\ny3\ny4\ny5\ny6\ny7\ny8\ny9\ny10\ny11\ny12\ny13\ny14\ny15\ny16\ny17\ny18\ny19\n\n\n(1)\n(2)\n(3)\n(4)\n(5)\n(6)\n(7)\n(8)\n(9)\n(10)\n(11)\n(12)\n(13)\n(14)\n(15)\n(16)\n(17)\n(18)\n(19)\n(20)\n\n\n\n\ncoef\n\n\nX0\n-0.108\n(0.103)\n-0.152\n(0.116)\n-0.243*\n(0.113)\n-0.026\n(0.112)\n-0.158\n(0.109)\n-0.132\n(0.108)\n-0.155\n(0.104)\n-0.180\n(0.114)\n-0.254*\n(0.111)\n-0.157\n(0.106)\n-0.066\n(0.109)\n-0.005\n(0.115)\n-0.214*\n(0.101)\n-0.183\n(0.115)\n-0.007\n(0.099)\n-0.138\n(0.105)\n-0.104\n(0.107)\n-0.138\n(0.111)\n-0.102\n(0.110)\n-0.154\n(0.098)\n\n\nX1\n0.538***\n(0.099)\n0.493***\n(0.112)\n0.589***\n(0.109)\n0.503***\n(0.108)\n0.340**\n(0.106)\n0.493***\n(0.104)\n0.568***\n(0.100)\n0.590***\n(0.110)\n0.502***\n(0.107)\n0.505***\n(0.102)\n0.375***\n(0.105)\n0.411***\n(0.111)\n0.452***\n(0.098)\n0.586***\n(0.111)\n0.438***\n(0.096)\n0.558***\n(0.101)\n0.408***\n(0.103)\n0.442***\n(0.107)\n0.498***\n(0.106)\n0.572***\n(0.095)\n\n\nX2\n0.081\n(0.101)\n0.026\n(0.114)\n0.094\n(0.111)\n0.094\n(0.110)\n0.008\n(0.108)\n-0.036\n(0.106)\n-0.054\n(0.102)\n-0.014\n(0.112)\n-0.043\n(0.109)\n-0.042\n(0.104)\n0.128\n(0.107)\n-0.043\n(0.113)\n0.039\n(0.099)\n0.053\n(0.113)\n-0.048\n(0.097)\n0.027\n(0.103)\n-0.021\n(0.105)\n0.019\n(0.109)\n0.015\n(0.108)\n-0.106\n(0.097)\n\n\nX3\n-0.068\n(0.104)\n-0.110\n(0.117)\n-0.033\n(0.114)\n-0.098\n(0.113)\n-0.127\n(0.110)\n-0.086\n(0.109)\n-0.056\n(0.104)\n-0.094\n(0.115)\n-0.092\n(0.112)\n-0.064\n(0.107)\n-0.099\n(0.110)\n-0.003\n(0.116)\n0.032\n(0.102)\n-0.157\n(0.116)\n-0.085\n(0.100)\n-0.017\n(0.106)\n-0.147\n(0.108)\n-0.027\n(0.111)\n-0.067\n(0.110)\n-0.088\n(0.099)\n\n\nX4\n-0.063\n(0.101)\n0.013\n(0.114)\n-0.142\n(0.111)\n0.002\n(0.110)\n0.086\n(0.107)\n-0.092\n(0.106)\n-0.059\n(0.102)\n0.030\n(0.112)\n-0.013\n(0.109)\n-0.067\n(0.104)\n0.068\n(0.107)\n-0.134\n(0.113)\n-0.012\n(0.099)\n-0.021\n(0.112)\n0.046\n(0.097)\n0.076\n(0.103)\n-0.033\n(0.105)\n-0.019\n(0.108)\n-0.073\n(0.107)\n0.061\n(0.096)\n\n\nIntercept\n-0.007\n(0.100)\n-0.061\n(0.113)\n-0.010\n(0.110)\n0.060\n(0.109)\n-0.035\n(0.107)\n0.003\n(0.105)\n-0.013\n(0.101)\n-0.014\n(0.111)\n-0.029\n(0.108)\n0.063\n(0.103)\n-0.003\n(0.106)\n0.071\n(0.112)\n0.117\n(0.098)\n0.022\n(0.112)\n-0.013\n(0.097)\n-0.034\n(0.102)\n0.054\n(0.104)\n-0.013\n(0.108)\n0.027\n(0.107)\n0.053\n(0.096)\n\n\nstats\n\n\nObservations\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n\n\nS.E. type\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\niid\n\n\nR2\n0.259\n0.202\n0.264\n0.214\n0.146\n0.226\n0.288\n0.269\n0.239\n0.238\n0.151\n0.149\n0.207\n0.273\n0.218\n0.267\n0.186\n0.170\n0.213\n0.333\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe will now study power more systematically via a simulation. More concretely, we will compute how often we detect the true effect of X1 on Y1, Y2, …, etc given a fixed sample size \\(N\\) using “uncorrected” p-values, the Bonferroni, Romano-Wolf and Westfall-Young methods.\n\ndef compute_power(seed, rho, effect):\n    \"Simulate data, estimate models, and compute power.\"\n    data = get_data_true_effect(\n        N, n_covariates, n_depvars, rho, seed=seed, effect=effect\n    )\n    fit = pf.feols(\n        fml=fml, data=data, vcov=\"hetero\"\n    )  # model '1' regresses on Y1 - we're only interested in the power of this specific test\n    df = fit.tidy().reset_index().set_index(\"Coefficient\").xs(\"X1\")\n\n    df[\"Pr(&gt;|t|) detect\"] = df[\"Pr(&gt;|t|)\"] &lt; 0.05\n    df[\"Bonferroni detect\"] = (\n        pf.bonferroni(fit, param=\"X1\").xs(\"Bonferroni Pr(&gt;|t|)\").values &lt; 0.05\n    )\n    df[\"rwolf detect\"] = (\n        pf.rwolf(fit, param=\"X1\", reps=200, seed=seed * 11).xs(\"RW Pr(&gt;|t|)\").values\n        &lt; 0.05\n    )\n    df[\"wyoung detect\"] = (\n        pf.wyoung(fit, param=\"X1\", reps=200, seed=seed * 11).xs(\"WY Pr(&gt;|t|)\").values\n        &lt; 0.05\n    )\n\n    # Compute family rejection means\n    detect_effect = {\n        \"Pr(&gt;|t|) detect effect\": df[\"Pr(&gt;|t|) detect\"].mean(),\n        \"Bonferroni detect effect\": df[\"Bonferroni detect\"].mean(),\n        \"rwolf detect effect\": df[\"rwolf detect\"].mean(),\n        \"wyoung detect effect\": df[\"wyoung detect\"].mean(),\n    }\n\n    detect_effect_df = pd.DataFrame(detect_effect, index=[effect])\n    return detect_effect_df\n\n\ndef run_power_simulation(n_iter, rho, effect, nthreads=-1):\n    \"Run simulation for power.\"\n    seeds = list(range(n_iter))\n    results = Parallel(n_jobs=nthreads)(\n        delayed(compute_power)(seed, rho=rho, effect=effect) for seed in tqdm(seeds)\n    )\n\n    return pd.concat(results).mean()\n\n\nrun_power_simulation(n_iter=1000, rho=0.5, effect=0.4)\n\n  0%|          | 0/1000 [00:00&lt;?, ?it/s]c:\\Users\\alexa\\Documents\\pyfixest\\.pixi\\envs\\dev\\Lib\\site-packages\\joblib\\externals\\loky\\process_executor.py:752: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.\n  warnings.warn(\n100%|██████████| 1000/1000 [12:00&lt;00:00,  1.39it/s]\n\n\nPr(&gt;|t|) detect effect      0.97045\nBonferroni detect effect    0.78485\nrwolf detect effect         0.86985\nwyoung detect effect        0.86985\ndtype: float64\n\n\nWe see that the “unadjusted” method detects the “true effects” at the highest frequency with on average 97% correctly detected effects. Does this mean that we should use uncorrected tests then? Well, maybe, but these do not control the family-wise error rate. While we have a better chance to detect a true effect, we also have a higher risk of flagging false positives.\nAdditionally, it looks as if the rwolf and wyoung methods detect the true positives at a slightly higher rate than the Bonferroni method.\nDo these findings generalize to other effect sizes? We can check this by simply imposing different effects on the data generating process and repeating the previous exercise multiple times.\n\ndef run_power_simulation_vary_effect():\n    \"Run power simulations with varying effect sizes.\"\n    n_points = 10\n    max_val = 0.7\n\n    effects = (\n        np.sign(np.linspace(-1, 1, n_points))\n        * max_val\n        * (np.linspace(-1, 1, n_points) ** 2)\n    )\n\n    res_list = []\n    for effect_size in tqdm(effects):\n        res = run_power_simulation(n_iter=1000, rho=0.5, effect=effect_size)\n        res[\"effect\"] = effect_size\n        res_list.append(res)\n    return pd.concat(res_list, axis=1).T.set_index(\"effect\")\n\n\nres = run_power_simulation_vary_effect()\n\n100%|██████████| 1000/1000 [10:54&lt;00:00,  1.53it/s]\n100%|██████████| 1000/1000 [10:17&lt;00:00,  1.62it/s]\n100%|██████████| 1000/1000 [10:05&lt;00:00,  1.65it/s]\n100%|██████████| 1000/1000 [10:09&lt;00:00,  1.64it/s]\n100%|██████████| 1000/1000 [10:25&lt;00:00,  1.60it/s]\n100%|██████████| 1000/1000 [09:54&lt;00:00,  1.68it/s]\n100%|██████████| 1000/1000 [09:44&lt;00:00,  1.71it/s]\n100%|██████████| 1000/1000 [10:53&lt;00:00,  1.53it/s]\n100%|██████████| 1000/1000 [14:32&lt;00:00,  1.15it/s]\n100%|██████████| 1000/1000 [14:38&lt;00:00,  1.14it/s]\n100%|██████████| 10/10 [1:53:04&lt;00:00, 678.48s/it]\n\n\n\ncolumn_to_label_dict = {\n    \"Pr(&gt;|t|) detect effect\": \"Unadjusted\",\n    \"Bonferroni detect effect\": \"Bonferroni\",\n    \"rwolf detect effect\": \"RW\",\n    \"wyoung detect effect\": \"WY\",\n}\n\nplt.figure(figsize=(10, 6))\nline_styles = [\"-\", \"--\", \"-.\", \":\"]\nfor column, line_style in zip(res.columns, line_styles):\n    plt.plot(\n        res.index, res[column], linestyle=line_style, label=column_to_label_dict[column]\n    )\n\nplt.title(\"Power of Multiple Testing Correction Procedures\")\nplt.xlabel(\"Effect\")\nplt.ylabel(\"Proportion of correctly detected effects\")\nplt.legend()\nplt.grid()\nplt.show()\n\n\n\n\n\n\n\n\nWe see that for any simulated effect size, the Romano-Wolf and Westfall-Young methods detect a higher share of true positives than the Bonferroni method: they have higher power."
  },
  {
    "objectID": "multiple_testing.html#literature",
    "href": "multiple_testing.html#literature",
    "title": "Multiple Hypothesis Testing Corrections",
    "section": "Literature",
    "text": "Literature\n\nClarke, Damian, Joseph P. Romano, and Michael Wolf. “The Romano–Wolf multiple-hypothesis correction in Stata.” The Stata Journal 20.4 (2020): 812-843.\nRomano, Joseph P., and Michael Wolf. “Stepwise multiple testing as formalized data snooping.” Econometrica 73.4 (2005): 1237-1282.\nWestfall, Peter H., and S. Stanley Young. Resampling-based multiple testing: Examples and methods for p-value adjustment. Vol. 279. John Wiley & Sons, 1993."
  },
  {
    "objectID": "difference-in-differences.html",
    "href": "difference-in-differences.html",
    "title": "Difference-in-Differences Estimation",
    "section": "",
    "text": "PyFixest supports event study designs via the canonical two-way fixed effects design, the 2-Step imputation estimator, and local projections.\nSee also NBER SI methods lectures on Linear Panel Event Studies."
  },
  {
    "objectID": "difference-in-differences.html#setup",
    "href": "difference-in-differences.html#setup",
    "title": "Difference-in-Differences Estimation",
    "section": "Setup",
    "text": "Setup\n\nfrom importlib import resources\n\nimport pandas as pd\n\nimport pyfixest as pf\nfrom pyfixest.report.utils import rename_event_study_coefs\nfrom pyfixest.utils.dgps import get_sharkfin\n\n%load_ext watermark\n%watermark --iversions\n%load_ext autoreload\n%autoreload 2\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\npandas  : 2.2.3\npyfixest: 0.27.0\n\n\n\n\n# one-shot adoption data - parallel trends is true\ndf_one_cohort = get_sharkfin()\ndf_one_cohort.head()\n\n\n\n\n\n\n\n\nunit\nyear\ntreat\nY\never_treated\n\n\n\n\n0\n0\n0\n0\n1.629307\n0\n\n\n1\n0\n1\n0\n0.825902\n0\n\n\n2\n0\n2\n0\n0.208988\n0\n\n\n3\n0\n3\n0\n-0.244739\n0\n\n\n4\n0\n4\n0\n0.804665\n0\n\n\n\n\n\n\n\n\n# multi-cohort adoption data\ndf_multi_cohort = pd.read_csv(\n    resources.files(\"pyfixest.did.data\").joinpath(\"df_het.csv\")\n)\ndf_multi_cohort.head()\n\n\n\n\n\n\n\n\nunit\nstate\ngroup\nunit_fe\ng\nyear\nyear_fe\ntreat\nrel_year\nrel_year_binned\nerror\nte\nte_dynamic\ndep_var\n\n\n\n\n0\n1\n33\nGroup 2\n7.043016\n2010\n1990\n0.066159\nFalse\n-20.0\n-6\n-0.086466\n0\n0.0\n7.022709\n\n\n1\n1\n33\nGroup 2\n7.043016\n2010\n1991\n-0.030980\nFalse\n-19.0\n-6\n0.766593\n0\n0.0\n7.778628\n\n\n2\n1\n33\nGroup 2\n7.043016\n2010\n1992\n-0.119607\nFalse\n-18.0\n-6\n1.512968\n0\n0.0\n8.436377\n\n\n3\n1\n33\nGroup 2\n7.043016\n2010\n1993\n0.126321\nFalse\n-17.0\n-6\n0.021870\n0\n0.0\n7.191207\n\n\n4\n1\n33\nGroup 2\n7.043016\n2010\n1994\n-0.106921\nFalse\n-16.0\n-6\n-0.017603\n0\n0.0\n6.918492"
  },
  {
    "objectID": "difference-in-differences.html#examining-treatment-timing",
    "href": "difference-in-differences.html#examining-treatment-timing",
    "title": "Difference-in-Differences Estimation",
    "section": "Examining Treatment Timing",
    "text": "Examining Treatment Timing\nBefore any DiD estimation, we need to examine the treatment timing, since it is crucial to our choice of estimator.\n\npf.panelview(\n    df_one_cohort,\n    unit=\"unit\",\n    time=\"year\",\n    treat=\"treat\",\n    collapse_to_cohort=True,\n    sort_by_timing=True,\n    ylab=\"Cohort\",\n    xlab=\"Year\",\n    title=\"Treatment Assignment Cohorts\",\n    figsize=(6, 5),\n)\n\n\n\n\n\n\n\n\n\npf.panelview(\n    df_multi_cohort,\n    unit=\"unit\",\n    time=\"year\",\n    treat=\"treat\",\n    collapse_to_cohort=True,\n    sort_by_timing=True,\n    ylab=\"Cohort\",\n    xlab=\"Year\",\n    title=\"Treatment Assignment Cohorts\",\n    figsize=(6, 5),\n)\n\n\n\n\n\n\n\n\nWe immediately see that we have staggered adoption of treatment in the second case, which implies that a naive application of 2WFE might yield biased estimates under substantial effect heterogeneity.\nWe can also plot treatment assignment in a disaggregated fashion, which gives us a sense of cohort sizes.\n\npf.panelview(\n    df_multi_cohort,\n    unit=\"unit\",\n    time=\"year\",\n    treat=\"treat\",\n    sort_by_timing=True,\n    ylab=\"Unit\",\n    xlab=\"Year\",\n    title=\"Treatment Assignment (all units)\",\n    figsize=(6, 5),\n)"
  },
  {
    "objectID": "difference-in-differences.html#inspecting-the-outcome-variable",
    "href": "difference-in-differences.html#inspecting-the-outcome-variable",
    "title": "Difference-in-Differences Estimation",
    "section": "Inspecting the Outcome Variable",
    "text": "Inspecting the Outcome Variable\npf.panelview() further allows us to inspect the “outcome” variable over time:\n\npf.panelview(\n    df_multi_cohort,\n    outcome=\"dep_var\",\n    unit=\"unit\",\n    time=\"year\",\n    treat=\"treat\",\n    collapse_to_cohort=True,\n    title=\"Outcome Plot\",\n    legend=True,\n    figsize=(7, 2.5),\n)\n\n\n\n\n\n\n\n\nWe immediately see that the first cohort is switched into treatment in 2000, while the second cohort is switched into treatment by 2010. Before each cohort is switched into treatment, the trends are parallel.\nWe can additionally inspect individual units by dropping the collapse_to_cohort argument. Because we have a large sample, we might want to inspect only a subset of units.\n\npf.panelview(\n    df_multi_cohort,\n    outcome=\"dep_var\",\n    unit=\"unit\",\n    time=\"year\",\n    treat=\"treat\",\n    subsamp=100,\n    title = \"Outcome Plot\",\n    legend=True,\n    figsize=(7, 2.5),\n)"
  },
  {
    "objectID": "difference-in-differences.html#one-shot-adoption-static-and-dynamic-specifications",
    "href": "difference-in-differences.html#one-shot-adoption-static-and-dynamic-specifications",
    "title": "Difference-in-Differences Estimation",
    "section": "One-shot adoption: Static and Dynamic Specifications",
    "text": "One-shot adoption: Static and Dynamic Specifications\nAfter taking a first look at the data, let’s turn to estimation. We return to the df_one_cohort data set (without staggered treatment rollout).\n\nfit_static_twfe = pf.feols(\n    \"Y ~ treat | unit + year\",\n    df_one_cohort,\n    vcov={\"CRV1\": \"unit\"},\n)\nfit_static_twfe.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: unit+year\nInference:  CRV1\nObservations:  30000\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| treat         |      0.206 |        0.052 |     3.929 |      0.000 |  0.103 |   0.308 |\n---\nRMSE: 0.701 R2: 0.905 R2 Within: 0.003 \n\n\nSince this is a single-cohort dataset, this estimate is consistent for the ATT under parallel trends. We can estimate heterogeneous effects by time by interacting time with the treated group:\n\nfit_dynamic_twfe = pf.feols(\n    \"Y ~ i(year, ever_treated,  ref = 14) | unit + year\",\n    df_one_cohort,\n    vcov={\"CRV1\": \"unit\"},\n)\n\n\nfit_dynamic_twfe.iplot(\n    coord_flip=False,\n    title=\"Event Study\",\n    figsize=[1200, 400],\n    yintercept=0,\n    xintercept=13.5,\n    labels=rename_event_study_coefs(fit_dynamic_twfe._coefnames),\n)\n\n   \n   \n\n\nEvent study plots like this are very informative, as they allow us to visually inspect the parallel trends assumption and also the dynamic effects of the treatment.\nBased on a cursory glance, one would conclude that parallel trends does not hold because one of the pre-treatment coefficient has a confidence interval that does not include zero. However, we know that parallel trends is true because the treatment is randomly assigned in the underlying DGP."
  },
  {
    "objectID": "difference-in-differences.html#pointwise-vs-simultaneous-inference-in-event-studies",
    "href": "difference-in-differences.html#pointwise-vs-simultaneous-inference-in-event-studies",
    "title": "Difference-in-Differences Estimation",
    "section": "Pointwise vs Simultaneous Inference in Event Studies",
    "text": "Pointwise vs Simultaneous Inference in Event Studies\nThis is an example of a false positive in testing for pre-trends produced by pointwise inference (where each element of the coefficient vector is tested separately).\nAs an alternative, we can use simultaneous confidence bands of the form \\([a, b] = ([a_k, b_k])_{k=1}^K\\) such that\n\\[\nP(\\beta \\in [a, b]) = P(\\beta_k \\in [a_k, b_k] \\forall k) \\rightarrow 1 - \\alpha\n\\]\nThese bands can be constructed by using a carefully chosen critical value \\(c\\) that accounts for the covariance between coefficients using the multiplier bootstrap. In pointwise inference, the critical value is \\(c = z_{1 - \\alpha/2} = 1.96\\) for \\(\\alpha = 0.05\\); the corresponding critical value for simultaneous inference is typically larger. These are also known as sup-t bands in the literature (see lec 3 of the NBER SI methods lectures linked above).\nThis is implemented in the confint(joint=True) method in the feols class. If we pass the joint='both' argument to iplot, we get the simultaneous confidence bands (for all event study coefficients) in addition to the pointwise confidence intervals. Note that simultaneous inference for all event study coefficients may be overly conservative, especially when the number of coefficients is large; one may instead choose to perform joint inference for all pre-treatment coefficients and all post-treatment coefficients separately.\n\nfit_dynamic_twfe.iplot(\n    coord_flip=False,\n    title=\"Event Study\",\n    figsize=[1200, 400],\n    yintercept=0,\n    xintercept=13.5,\n    joint=\"both\",\n    labels=rename_event_study_coefs(fit_dynamic_twfe._coefnames),\n)\n\n   \n   \n\n\nThe joint confidence bands are wider than the pointwise confidence intervals, and they include zero for all pre-treatment coefficients. This is consistent with the parallel trends assumption."
  },
  {
    "objectID": "difference-in-differences.html#event-study-under-staggered-adoption-via-feols-did2s-and-lpdid",
    "href": "difference-in-differences.html#event-study-under-staggered-adoption-via-feols-did2s-and-lpdid",
    "title": "Difference-in-Differences Estimation",
    "section": "Event Study under Staggered Adoption via feols(), did2s() and lpdid()",
    "text": "Event Study under Staggered Adoption via feols(), did2s() and lpdid()\nWe now return to the data set with staggered treatment rollout, df_multi_cohort.\n\nTwo-Way Fixed Effects\nAs a baseline model, we can estimate a simple two-way fixed effects DiD regression via feols():\n\nfit_twfe = pf.feols(\n    \"dep_var ~ i(rel_year, ref=-1.0) | state + year\",\n    df_multi_cohort,\n    vcov={\"CRV1\": \"state\"},\n)\n\n\n\nGardner’s 2-Step Estimator\nTo do the same via Gardners 2-stage estimator, we employ the the pf.did2s() function:\n\nfit_did2s = pf.did2s(\n    df_multi_cohort,\n    yname=\"dep_var\",\n    first_stage=\"~ 0 | state + year\",\n    second_stage=\"~i(rel_year,ref=-1.0)\",\n    treatment=\"treat\",\n    cluster=\"state\",\n)\n\n\n\nLocal Projections (Dube et al)\nLast, we can estimate the ATT for each time period via local projections by using the lpdid() function:\n\nfit_lpdid = pf.lpdid(\n    data=df_multi_cohort,\n    yname=\"dep_var\",\n    gname=\"g\",\n    tname=\"year\",\n    idname=\"unit\",\n    vcov={\"CRV1\": \"state\"},\n    pre_window=-20,\n    post_window=20,\n    att=False,\n)\n\nLet’s look at some results:\n\nfigsize = [1200, 400]\n\n\nfit_twfe.iplot(\n    coord_flip=False,\n    title=\"TWFE-Estimator\",\n    figsize=figsize,\n    xintercept=18.5,\n    yintercept=0,\n    labels=rename_event_study_coefs(fit_twfe._coefnames),  # rename coefficients\n).show()\n\n   \n   \n\n\n\nfit_lpdid.iplot(\n    coord_flip=False,\n    title=\"Local-Projections-Estimator\",\n    figsize=figsize,\n    yintercept=0,\n    xintercept=18.5,\n).show()\n\n   \n   \n\n\nWhat if we are not interested in the ATT per treatment period, but in a pooled effects?\n\nfit_twfe = pf.feols(\n    \"dep_var ~ i(treat) | unit + year\",\n    df_multi_cohort,\n    vcov={\"CRV1\": \"state\"},\n)\n\nfit_did2s = pf.did2s(\n    df_multi_cohort,\n    yname=\"dep_var\",\n    first_stage=\"~ 0 | unit + year\",\n    second_stage=\"~i(treat)\",\n    treatment=\"treat\",\n    cluster=\"state\",\n)\n\nfit_lpdid = pf.lpdid(\n    data=df_multi_cohort,\n    yname=\"dep_var\",\n    gname=\"g\",\n    tname=\"year\",\n    idname=\"unit\",\n    vcov={\"CRV1\": \"state\"},\n    pre_window=-20,\n    post_window=20,\n    att=True,\n)\npd.concat(\n    [\n        fit_twfe.tidy().assign(estimator=\"TWFE\"),\n        fit_did2s.tidy().assign(estimator=\"DID2s\"),\n        fit_lpdid.tidy().assign(estimator=\"LPDID\").drop(\"N\", axis=1),\n    ],\n    axis=0,\n)\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\nestimator\n\n\n\n\nC(treat)[T.True]\n1.982540\n0.019331\n102.556180\n0.0\n1.943439\n2.021642\nTWFE\n\n\nC(treat)[T.True]\n2.230482\n0.024709\n90.271437\n0.0\n2.180504\n2.280460\nDID2s\n\n\ntreat_diff\n2.506746\n0.071357\n35.129648\n0.0\n2.362413\n2.651080\nLPDID"
  },
  {
    "objectID": "compare-fixest-pyfixest.html",
    "href": "compare-fixest-pyfixest.html",
    "title": "Does PyFixest match fixest?",
    "section": "",
    "text": "This vignette compares estimation results from fixest with pyfixest via the rpy2 package."
  },
  {
    "objectID": "compare-fixest-pyfixest.html#setup",
    "href": "compare-fixest-pyfixest.html#setup",
    "title": "Does PyFixest match fixest?",
    "section": "Setup",
    "text": "Setup\n\nimport pandas as pd\nimport rpy2.robjects as ro\nfrom rpy2.robjects import pandas2ri\nfrom rpy2.robjects.packages import importr\n\nimport pyfixest as pf\n\n# Activate pandas2ri\npandas2ri.activate()\n\n# Import R packages\nfixest = importr(\"fixest\")\nstats = importr(\"stats\")\nbroom = importr(\"broom\")\n\n# IPython magic commands for autoreloading\n%load_ext autoreload\n%autoreload 2\n\n# Get data using pyfixest\ndata = pf.get_data(model=\"Feols\", N=10_000, seed=99292)"
  },
  {
    "objectID": "compare-fixest-pyfixest.html#ordinary-least-squares-ols",
    "href": "compare-fixest-pyfixest.html#ordinary-least-squares-ols",
    "title": "Does PyFixest match fixest?",
    "section": "Ordinary Least Squares (OLS)",
    "text": "Ordinary Least Squares (OLS)\n\nIID Inference\nFirst, we estimate a model via `pyfixest. We compute “iid” standard errors.\n\nfit = pf.feols(fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, vcov=\"iid\")\n\nWe estimate the same model with weights:\n\nfit_weights = pf.feols(\n    fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, weights=\"weights\", vcov=\"iid\"\n)\n\nVia r-fixest and rpy2, we get\n\nr_fit = fixest.feols(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    vcov=\"iid\",\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\n\nr_fit_weights = fixest.feols(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    weights=ro.Formula(\"~weights\"),\n    vcov=\"iid\",\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\n\n\nR[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\nR[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\nLet’s compare how close the covariance matrices are:\n\nfit_vcov = fit._vcov\nr_vcov = stats.vcov(r_fit)\nfit_vcov - r_vcov\n\narray([[-7.04731412e-19, -3.34180967e-22],\n       [-3.34594558e-22, -1.38913403e-19]])\n\n\nAnd for WLS:\n\nfit_weights._vcov - stats.vcov(r_fit_weights)\n\narray([[ 1.68051337e-18, -1.69406589e-21],\n       [-1.69406589e-21, -1.49077799e-19]])\n\n\nWe conclude by comparing all estimation results via the tidy methods:\n\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n0.112019\n0.016947\n6.610087\n4.036971e-11\n0.078800\n0.145238\n\n\nX2\n0.732788\n0.004595\n159.474281\n0.000000e+00\n0.723781\n0.741795\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(r_fit)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n0.112019\n0.016947\n6.610087\n0.0\n\n\n1\nX2\n0.732788\n0.004595\n159.474281\n0.0\n\n\n\n\n\n\n\n\nfit_weights.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n0.123687\n0.016880\n7.327370\n2.529088e-13\n0.090598\n0.156775\n\n\nX2\n0.732244\n0.004584\n159.741845\n0.000000e+00\n0.723258\n0.741229\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(r_fit_weights)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n0.123687\n0.01688\n7.32737\n0.0\n\n\n1\nX2\n0.732244\n0.004584\n159.741845\n0.0\n\n\n\n\n\n\n\n\n\nHeteroskedastic Errors\nWe repeat the same exercise with heteroskedastic (HC1) errors:\n\nfit = pf.feols(fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, vcov=\"hetero\")\nfit_weights = pf.feols(\n    fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, vcov=\"hetero\", weights=\"weights\"\n)\n\n\nr_fit = fixest.feols(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    vcov=\"hetero\",\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\n\nr_fit_weights = fixest.feols(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    weights=ro.Formula(\"~weights\"),\n    vcov=\"hetero\",\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\n\n\nAs before, we compare the variance covariance matrices:\n\nfit._vcov - stats.vcov(r_fit)\n\narray([[-1.61925594e-16, -2.13306719e-17],\n       [-2.13306719e-17, -5.39593869e-17]])\n\n\n\nfit_weights._vcov - stats.vcov(r_fit_weights)\n\narray([[-2.04968421e-16, -9.53780274e-18],\n       [-9.53780274e-18, -3.03136151e-17]])\n\n\nWe conclude by comparing all estimation results via the tidy methods:\n\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n0.112019\n0.017009\n6.585966\n4.746648e-11\n0.078678\n0.145359\n\n\nX2\n0.732788\n0.004553\n160.940355\n0.000000e+00\n0.723863\n0.741713\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(r_fit)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n0.112019\n0.017009\n6.585966\n0.0\n\n\n1\nX2\n0.732788\n0.004553\n160.940355\n0.0\n\n\n\n\n\n\n\n\nfit_weights.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n0.123687\n0.019361\n6.388512\n1.749667e-10\n0.085736\n0.161638\n\n\nX2\n0.732244\n0.005140\n142.453692\n0.000000e+00\n0.722168\n0.742319\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(r_fit_weights)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n0.123687\n0.019361\n6.388512\n0.0\n\n\n1\nX2\n0.732244\n0.00514\n142.453692\n0.0\n\n\n\n\n\n\n\n\n\nCluster-Robust Errors\nWe conclude with cluster robust errors.\n\nfit = pf.feols(fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, vcov={\"CRV1\": \"f1\"})\nfit_weights = pf.feols(\n    fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, vcov={\"CRV1\": \"f1\"}, weights=\"weights\"\n)\n\nr_fit = fixest.feols(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    vcov=ro.Formula(\"~f1\"),\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\nr_fit_weights = fixest.feols(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    weights=ro.Formula(\"~weights\"),\n    vcov=ro.Formula(\"~f1\"),\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\n\n\n\nfit._vcov - stats.vcov(r_fit)\n\narray([[ 4.20345182e-16, -6.97319874e-17],\n       [-6.97328344e-17, -1.42199891e-17]])\n\n\n\nfit_weights._vcov - stats.vcov(r_fit_weights)\n\narray([[2.58961689e-16, 4.07331368e-16],\n       [4.07334756e-16, 1.79740391e-17]])\n\n\nWe conclude by comparing all estimation results via the tidy methods:\n\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n0.112019\n0.015816\n7.082626\n4.456304e-09\n0.080251\n0.143786\n\n\nX2\n0.732788\n0.004476\n163.724207\n0.000000e+00\n0.723798\n0.741778\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(r_fit)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n0.112019\n0.015816\n7.082626\n0.0\n\n\n1\nX2\n0.732788\n0.004476\n163.724207\n0.0\n\n\n\n\n\n\n\n\nfit_weights.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n0.123687\n0.018311\n6.754616\n1.452848e-08\n0.086907\n0.160466\n\n\nX2\n0.732244\n0.005249\n139.495536\n0.000000e+00\n0.721700\n0.742787\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(r_fit_weights)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n0.123687\n0.018311\n6.754616\n0.0\n\n\n1\nX2\n0.732244\n0.005249\n139.495536\n0.0"
  },
  {
    "objectID": "compare-fixest-pyfixest.html#poisson-regression",
    "href": "compare-fixest-pyfixest.html#poisson-regression",
    "title": "Does PyFixest match fixest?",
    "section": "Poisson Regression",
    "text": "Poisson Regression\n\ndata = pf.get_data(model=\"Fepois\")\n\n\nfit_iid = pf.fepois(fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, vcov=\"iid\", iwls_tol=1e-10)\nfit_hetero = pf.fepois(\n    fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, vcov=\"hetero\", iwls_tol=1e-10\n)\nfit_crv = pf.fepois(\n    fml=\"Y ~ X1 + X2 | f1 + f2\", data=data, vcov={\"CRV1\": \"f1\"}, iwls_tol=1e-10\n)\n\nfit_r_iid = fixest.fepois(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    vcov=\"iid\",\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\n\nfit_r_hetero = fixest.fepois(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    vcov=\"hetero\",\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\n\nfit_r_crv = fixest.fepois(\n    ro.Formula(\"Y ~ X1 + X2 | f1 + f2\"),\n    data=data,\n    vcov=ro.Formula(\"~f1\"),\n    ssc=fixest.ssc(True, \"none\", True, \"min\", \"min\", False),\n)\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\nWARNING:rpy2.rinterface_lib.callbacks:R[write to console]: NOTE: 3 observations removed because of NA values (LHS: 1, RHS: 1, Fixed-effects: 1).\n\n\n\n\nfit_iid._vcov - stats.vcov(fit_r_iid)\n\narray([[ 1.20791284e-08, -6.55604931e-10],\n       [-6.55604931e-10,  1.69958097e-09]])\n\n\n\nfit_hetero._vcov - stats.vcov(fit_r_hetero)\n\narray([[ 2.18101847e-08, -7.38711972e-10],\n       [-7.38711972e-10,  3.07587753e-09]])\n\n\n\nfit_crv._vcov - stats.vcov(fit_r_crv)\n\narray([[ 1.58300904e-08, -1.20806815e-10],\n       [-1.20806815e-10,  3.17512746e-09]])\n\n\nWe conclude by comparing all estimation results via the tidy methods:\n\nfit_iid.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n-0.006591\n0.040758\n-0.161714\n0.871531\n-0.086475\n0.073293\n\n\nX2\n-0.014924\n0.010994\n-1.357466\n0.174633\n-0.036472\n0.006624\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(fit_r_iid)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n-0.006591\n0.040758\n-0.161714\n0.871531\n\n\n1\nX2\n-0.014924\n0.010994\n-1.357476\n0.17463\n\n\n\n\n\n\n\n\nfit_hetero.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n-0.006591\n0.039145\n-0.168376\n0.866287\n-0.083314\n0.070132\n\n\nX2\n-0.014924\n0.010501\n-1.421145\n0.155275\n-0.035506\n0.005658\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(fit_r_hetero)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n-0.006591\n0.039145\n-0.168377\n0.866286\n\n\n1\nX2\n-0.014924\n0.010501\n-1.421165\n0.155269\n\n\n\n\n\n\n\n\nfit_crv.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n-0.006591\n0.034745\n-0.189697\n0.849547\n-0.074691\n0.061509\n\n\nX2\n-0.014924\n0.010303\n-1.448570\n0.147458\n-0.035117\n0.005269\n\n\n\n\n\n\n\n\npd.DataFrame(broom.tidy_fixest(fit_r_crv)).T\n\n\n\n\n\n\n\n\n0\n1\n2\n3\n4\n\n\n\n\n0\nX1\n-0.006591\n0.034745\n-0.189698\n0.849546\n\n\n1\nX2\n-0.014924\n0.010302\n-1.448592\n0.147452"
  },
  {
    "objectID": "changelog.html",
    "href": "changelog.html",
    "title": "Changelog",
    "section": "",
    "text": "Adds a pf.feglm() function that supports GLMs with normal and binomial families (gaussian, logit, probit) without fixed effects. Fixed effects support is work in progress.\nFix a bug that caused reindexing of LPDID._coeftable when calling LPDID.iplot(). As a result, a second call of LPDID.iplot() would fail."
  },
  {
    "objectID": "changelog.html#pyfixest-0.28.0-in-development-can-be-installed-from-github",
    "href": "changelog.html#pyfixest-0.28.0-in-development-can-be-installed-from-github",
    "title": "Changelog",
    "section": "",
    "text": "Adds a pf.feglm() function that supports GLMs with normal and binomial families (gaussian, logit, probit) without fixed effects. Fixed effects support is work in progress.\nFix a bug that caused reindexing of LPDID._coeftable when calling LPDID.iplot(). As a result, a second call of LPDID.iplot() would fail."
  },
  {
    "objectID": "changelog.html#pyfixest-0.27.0",
    "href": "changelog.html#pyfixest-0.27.0",
    "title": "Changelog",
    "section": "PyFixest 0.27.0",
    "text": "PyFixest 0.27.0\n\nAdds support for Gelbach’s (JoLe 2016) Regression Decomposition method using a decompose() method for Feols.\nAdds support for the multiple hypothesis correction by Westfall & Young via the pf.wyoung() function.\nInput data frames to pf.feols() and pf.fepois() are now converted to pandas via narwhals. As a result, users can not provide duckdb or ibis tables as inputs, as well as pandas and polars data frames. polars and pyarrow are dropped as a dependencies.\nFixes a bug in the wildboottest method, which incorrectly used to run a regression on the demeaned dependend variable in case it was applied after a fixed effects regression. My apologies for that!\nFixes a bug in the ritest method, which would use randomization inference coefficients instead of t-statistics, leading to incorrect results. This has consequences for the rwolf() function, which, in case of running ri-inference, would default to run the randomization-t. My apolgies!\nAdds a vignette on multiple testing corrections.\nAdds a vignette on Gelbach’s regression decomposition."
  },
  {
    "objectID": "changelog.html#pyfixest-0.22.0---0.25.4",
    "href": "changelog.html#pyfixest-0.22.0---0.25.4",
    "title": "Changelog",
    "section": "PyFixest 0.22.0 - 0.25.4",
    "text": "PyFixest 0.22.0 - 0.25.4\nSee the github changelog for details: link."
  },
  {
    "objectID": "changelog.html#pyfixest-0.22.0",
    "href": "changelog.html#pyfixest-0.22.0",
    "title": "Changelog",
    "section": "PyFixest 0.22.0",
    "text": "PyFixest 0.22.0\n\nChanges\n\nFix bug in wildboottest method @s3alfisc (#506)\ndocs: add sanskriti2005 as a contributor for infra @allcontributors (#503)\nInfra: added the release-drafter for automation of release notes @sanskriti2005 (#502)\nFix broken link in contributing.md @s3alfisc (#499)\ndocs: add leostimpfle as a contributor for bug @allcontributors (#495)\nUpdate justfile @leostimpfle (#494)\ndocs: add baggiponte as a contributor for doc @allcontributors (#490)\ndocs: improve installation section @baggiponte (#489)\nBump tornado from 6.4 to 6.4.1 @dependabot (#487)\ndocs: add leostimpfle as a contributor for code @allcontributors (#478)\nFeols: speed up the creation of interacted fixed effects via fe1^fe2 syntax @leostimpfle (#475)\nrename resampling iterations to ‘reps’ in all methods @s3alfisc (#474)\nfix a lot of broken links throught the repo @s3alfisc (#472)\nMultiple readme fixes required after package was moved to py-econometrics project @s3alfisc (#450)\n\n\n\nInfrastructure\n\ninfrastructure: fix minor release drafter bugs @s3alfisc (#504)"
  },
  {
    "objectID": "changelog.html#pyfixest-0.21.0",
    "href": "changelog.html#pyfixest-0.21.0",
    "title": "Changelog",
    "section": "PyFixest 0.21.0",
    "text": "PyFixest 0.21.0\n\nAdd support for randomization inference via the ritest() method:\n\n\nimport pyfixest as pf\ndata = pf.get_data()\n\nfit = pf.feols(\"Y ~ X1\", data = data)\nfit.ritest(resampvar=\"X1=0\", reps = 1000)"
  },
  {
    "objectID": "changelog.html#pyfixest-0.20.0",
    "href": "changelog.html#pyfixest-0.20.0",
    "title": "Changelog",
    "section": "PyFixest 0.20.0",
    "text": "PyFixest 0.20.0\n\nThis version introduces MyPy type checks to the entire pyfixest codebase. Thanks to @juanitorduz for nudging me to get started with this =). It also fixes a handful of smaller bugs."
  },
  {
    "objectID": "changelog.html#pyfixest-0.19.0",
    "href": "changelog.html#pyfixest-0.19.0",
    "title": "Changelog",
    "section": "PyFixest 0.19.0",
    "text": "PyFixest 0.19.0\n\nFixes multiple smaller and larger performance regressions. The NYC-Taxi example regression now takes approximately 22 seconds to run (… if my laptopt is connected to a power charger)!\n\n\n%load_ext autoreload\n%autoreload 2\n\nimport duckdb\nimport time\nimport numpy as np\nimport pyfixest as pf\n\n# %%\nnyc = duckdb.sql(\n    '''\n    FROM 'C:/Users/alexa/Documents/nyc-taxi/**/*.parquet'\n    SELECT\n        tip_amount, trip_distance, passenger_count,\n        vendor_id, payment_type, dropoff_at,\n        dayofweek(dropoff_at) AS dofw\n    WHERE year = 2012 AND month &lt;= 3\n    '''\n    ).df()\n\n# convert dowf, vendor_id, payment_type to categorical\ntic = time.time()\nnyc[\"dofw\"] = nyc[\"dofw\"].astype(int)\nnyc[\"vendor_id\"] = nyc[\"vendor_id\"].astype(\"category\")\nnyc[\"payment_type\"] = nyc[\"payment_type\"].astype(\"category\")\nprint(f\"\"\"\n    I am convering columns of type 'objects' to 'categories' and 'int'data types outside\n    of the regression, hence I am cheating a bit. This saves {np.round(time.time() - tic)} seconds.\n    \"\"\"\n)\n#    I am convering columns of type 'objects' to 'categories' and 'int'data types outside\n#    of the regression, hence I am cheating a bit. This saves 7.0 seconds.\n\nrun = True\nif run:\n\n    # mock regression for JIT compilation\n    fit = pf.feols(\n        fml = \"tip_amount ~ trip_distance + passenger_count | vendor_id + payment_type + dofw\",\n        data = nyc.iloc[1:10_000],\n        copy_data = False,\n        store_data = False\n        )\n\n    import time\n    tic = time.time()\n    fit = pf.feols(\n        fml = \"tip_amount ~ trip_distance + passenger_count | vendor_id + payment_type + dofw\",\n        data = nyc,\n        copy_data = False, # saves a few seconds\n        store_data = False # saves a few second\n        )\n    passed = time.time() - tic\n    print(f\"Passed time is {np.round(passed)}.\")\n    # Passed time is 22.\n\n\nAdds three new function arguments to feols() and fepois(): copy_data, store_data, and fixef_tol.\nAdds support for frequency weights with the weights_type function argument.\n\n\nimport pyfixest as pf\n\ndata = pf.get_data(N = 10000, model = \"Fepois\")\ndf_weighted = data[[\"Y\", \"X1\", \"f1\"]].groupby([\"Y\", \"X1\", \"f1\"]).size().reset_index().rename(columns={0: \"count\"})\ndf_weighted[\"id\"] = list(range(df_weighted.shape[0]))\n\nprint(\"Dimension of the aggregated df:\", df_weighted.shape)\nprint(df_weighted.head())\n\nfit = pf.feols(\n    \"Y ~ X1 | f1\",\n    data = data\n)\nfit_weighted = pf.feols(\n    \"Y ~ X1 | f1\",\n    data = df_weighted,\n    weights = \"count\",\n    weights_type = \"fweights\"\n)\npf.etable([fit, fit_weighted], coef_fmt = \"b(se) \\n (t) \\n (p)\")\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\nDimension of the aggregated df: (1278, 5)\n     Y   X1   f1  count  id\n0  0.0  0.0  0.0     17   0\n1  0.0  0.0  1.0     11   1\n2  0.0  0.0  2.0     10   2\n3  0.0  0.0  3.0     17   3\n4  0.0  0.0  4.0     14   4\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n\n\n\n\ncoef\n\n\nX1\n0.001(0.012)\n(0.092)\n(0.927)\n0.001(0.012)\n(0.092)\n(0.927)\n\n\nfe\n\n\nf1\nx\nx\n\n\nstats\n\n\nObservations\n9997\n9997\n\n\nS.E. type\nby: f1\nby: f1\n\n\nR2\n0.011\n-\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient(Std. Error) (t-stats) (p-value)\n\n\n\n\n\n\n\n        \n\n\n\nBugfix: Wild Cluster Bootstrap Inference with Weights would compute unweighted standard errors. Sorry about that! WLS is not supported for the WCB.\nAdds support for CRV3 inference with weights."
  },
  {
    "objectID": "changelog.html#pyfixest-0.18.0",
    "href": "changelog.html#pyfixest-0.18.0",
    "title": "Changelog",
    "section": "PyFixest 0.18.0",
    "text": "PyFixest 0.18.0\n\nLarge Refactoring of Interal Processing of Model Formulas, in particular FixestFormulaParser and model_matrix_fixest. As a results, the code should be cleaner and more robust.\nThanks to the refactoring, we can now bump the required formulaic version to the stable 1.0.0 release.\nThe fml argument of model_matrix_fixest is deprecated. Instead, model_matrix_fixest now asks for a FixestFormula, which is essentially a dictionary with information on model specifications like a first stage formula (if applicable), dependent variables, fixed effects, etc.\nAdditionally, model_matrix_fixest now returns a dictionary instead of a tuple.\nBrings back fixed effects reference setting via i(var1, var2, ref) syntax. Deprecates the i_ref1, i_ref2 function arguments. I.e. it is again possible to e.g. run\n\n\nimport pyfixest as pf\ndata = pf.get_data()\n\nfit1 = pf.feols(\"Y ~ i(f1, X2)\", data=data)\nfit1.coef()[0:8]\n\nVia the ref syntax, via can set the reference level:\n\nfit2 = pf.feols(\"Y ~ i(f1, X2, ref = 1)\", data=data)\nfit2.coef()[0:8]"
  },
  {
    "objectID": "changelog.html#pyfixest-0.17.0",
    "href": "changelog.html#pyfixest-0.17.0",
    "title": "Changelog",
    "section": "PyFixest 0.17.0",
    "text": "PyFixest 0.17.0\n\nRestructures the codebase and reorganizes how users can interact with the pyfixest API. It is now recommended to use pyfixest in the following way:\n\nimport numpy as np\nimport pyfixest as pf\ndata = pf.get_data()\ndata[\"D\"] = data[\"X1\"] &gt; 0\nfit = pf.feols(\"Y ~ D + f1\", data = data)\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nIntercept\n0.778849\n0.170261\n4.574437\n0.000005\n0.444737\n1.112961\n\n\nD\n-1.402617\n0.152224\n-9.214140\n0.000000\n-1.701335\n-1.103899\n\n\nf1\n0.004774\n0.008058\n0.592508\n0.553645\n-0.011038\n0.020587\n\n\n\n\n\n\n\nThe update should not inroduce any breaking changes. Thanks to @Wenzhi-Ding for the PR!\nAdds support for simultaneous confidence intervals via a multiplier bootstrap. Thanks to @apoorvalal for the contribution!\n\nfit.confint(joint = True)\n\n\n\n\n\n\n\n\n2.5%\n97.5%\n\n\n\n\nIntercept\n0.381442\n1.176256\n\n\nD\n-1.757924\n-1.047309\n\n\nf1\n-0.014033\n0.023582\n\n\n\n\n\n\n\nAdds support for the causal cluster variance estimator by Abadie et al. (QJE, 2023) for OLS via the .ccv() method.\n\nfit.ccv(treatment = \"D\", cluster = \"group_id\")\n\nC:\\Users\\alexa\\Documents\\pyfixest\\pyfixest\\estimation\\feols_.py:1383: UserWarning: The initial model was not clustered. CRV1 inference is computed and stored in the model object.\n  warnings.warn(\n\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\n\n\nCCV\n-1.4026168622179929\n0.295093\n-4.753132\n0.000159\n-2.022585\n-0.782649\n\n\nCRV1\n-1.402617\n0.205132\n-6.837621\n0.000002\n-1.833584\n-0.97165"
  },
  {
    "objectID": "changelog.html#pyfixest-0.16.0",
    "href": "changelog.html#pyfixest-0.16.0",
    "title": "Changelog",
    "section": "PyFixest 0.16.0",
    "text": "PyFixest 0.16.0\n\nAdds multiple quality of life improvements for developers, thanks to NKeleher.\nAdds more options to customize etable() output thanks to Wenzhi-Ding.\nImplements Romano-Wolf and Bonferroni corrections for multiple testing in the multcomp module."
  },
  {
    "objectID": "changelog.html#pyfixest-0.15.",
    "href": "changelog.html#pyfixest-0.15.",
    "title": "Changelog",
    "section": "PyFixest 0.15.",
    "text": "PyFixest 0.15.\n\nAdds support for weighted least squares for feols().\nReduces testing time drastically by running tests on fewer random data samples. Qualitatively, the set of test remains identical.\nSome updates for future pandas compatibility."
  },
  {
    "objectID": "changelog.html#pyfixest-0.14.0",
    "href": "changelog.html#pyfixest-0.14.0",
    "title": "Changelog",
    "section": "PyFixest 0.14.0",
    "text": "PyFixest 0.14.0\n\nMoves the documentation to quartodoc.\nChanges all docstrings to numpy format.\nDifference-in-differences estimation functions now need to be imported via the pyfixest.did.estimation module:\n\n\nfrom pyfixest.did.estimation import did2s, lpdid, event_study"
  },
  {
    "objectID": "changelog.html#pyfixest-0.13.5",
    "href": "changelog.html#pyfixest-0.13.5",
    "title": "Changelog",
    "section": "PyFixest 0.13.5",
    "text": "PyFixest 0.13.5\n\nFixes a bug that lead to incorrect results when the dependent variable and all covariates (excluding the fixed effects) where integers."
  },
  {
    "objectID": "changelog.html#pyfixest-0.13.4",
    "href": "changelog.html#pyfixest-0.13.4",
    "title": "Changelog",
    "section": "PyFixest 0.13.4",
    "text": "PyFixest 0.13.4\n\nFixes a bug in etable() with IV’s that occurred because feols() does not report R2 statistics for IVs."
  },
  {
    "objectID": "changelog.html#pyfixest-0.13.2",
    "href": "changelog.html#pyfixest-0.13.2",
    "title": "Changelog",
    "section": "PyFixest 0.13.2",
    "text": "PyFixest 0.13.2\n\nFixes a bug in etable() and a warning in fixest_model_matrix that arose with higher pandas versions. Thanks to @aeturrell for reporting!"
  },
  {
    "objectID": "changelog.html#pyfixest-0.13.0",
    "href": "changelog.html#pyfixest-0.13.0",
    "title": "Changelog",
    "section": "PyFixest 0.13.0",
    "text": "PyFixest 0.13.0\n\nNew Features\n\nIntroduces a new pyfixest.did module which contains routines for Difference-in-Differences estimation.\nIntroduces support for basic versions of the local projections DiD estimator following Dube et al (2023)\nAdds a new vignette for Difference-in-Differences estimation.\nReports R2 values in etable()."
  },
  {
    "objectID": "changelog.html#pyfixest-0.12.0",
    "href": "changelog.html#pyfixest-0.12.0",
    "title": "Changelog",
    "section": "PyFixest 0.12.0",
    "text": "PyFixest 0.12.0\n\nEnhancements:\n\nGood performance improvements for singleton fixed effects detection. Thanks to @styfenschaer for the PR! See #229.\nUses the r2u project for installing R and R packages on github actions, with great performance improvements.\nAllows to pass polars data frames to feols(), fepois() and predict(). #232. Thanks to @vincentarelbundock for the suggestion!\n\n\n\nBug Fixes:\n\nMissing variables in features were not always handled correctly in predict() with newdata not None in the presence of missing data, which would lead to an error. See #246 for details.\nCategorical variables were not always handled correctly in predict() with newdata not None, because the number of fixed effects levels in newdata might be smaller than in data. In consequence, some levels were not found, which lead to an error. See #245 for details. Thanks to @jiafengkevinchen for the pointer!\nMulticollinearity checks for over-identified IV was not implemented correctly, which lead to a dimension error. See #236 for details. Thanks to @jiafengkevinchen for the pointer!\nThe number of degrees of freedom k was computed incorrectly if columns were dropped from the design matrix X in the presence of multicollinearity. See #235 for details. Thanks to @jiafengkevinchen for the pointer!\nIf all variables were dropped due to multicollinearity, an unclear and imprecise error message was produced. See #228 for details. Thanks to @manferdinig for the pointer!\nIf selection fixef_rm = 'singleton', feols() and fepois() would fail, which has been fixed. #192\n\n\n\nDependency Requirements\n\nFor now, sets formulaic versions to be 0.6.6 or lower as version 1.0.0 seems to have introduced a problem with the i() operator, See #244 for details.\nDrops dependency on pyhdfe."
  },
  {
    "objectID": "changelog.html#pyfixest-0.11.1",
    "href": "changelog.html#pyfixest-0.11.1",
    "title": "Changelog",
    "section": "PyFixest 0.11.1",
    "text": "PyFixest 0.11.1\n\nFixes some bugs around the computation of R-squared values (see issue #103).\nReports R-squared values again when calling .summary()."
  },
  {
    "objectID": "changelog.html#pyfixest-0.11.0",
    "href": "changelog.html#pyfixest-0.11.0",
    "title": "Changelog",
    "section": "PyFixest 0.11.0",
    "text": "PyFixest 0.11.0\n\nSignificant speedups for CRV1 inference."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.12",
    "href": "changelog.html#pyfixest-0.10.12",
    "title": "Changelog",
    "section": "PyFixest 0.10.12",
    "text": "PyFixest 0.10.12\nFixes a small bug with the separation check for poisson regression #138."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.11",
    "href": "changelog.html#pyfixest-0.10.11",
    "title": "Changelog",
    "section": "PyFixest 0.10.11",
    "text": "PyFixest 0.10.11\nFixes bugs with i(var1, var2) syntax introduced with PyFixest 0.10.10."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.10",
    "href": "changelog.html#pyfixest-0.10.10",
    "title": "Changelog",
    "section": "PyFixest 0.10.10",
    "text": "PyFixest 0.10.10\nFixes a bug with variable interactions via i(var) syntax. See issue #221."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.9",
    "href": "changelog.html#pyfixest-0.10.9",
    "title": "Changelog",
    "section": "PyFixest 0.10.9",
    "text": "PyFixest 0.10.9\nMakes etable() prettier and more informative."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.8",
    "href": "changelog.html#pyfixest-0.10.8",
    "title": "Changelog",
    "section": "PyFixest 0.10.8",
    "text": "PyFixest 0.10.8\n\nBreaking changes\nReference levels for the i() formula syntax can no longer be set within the formula, but need to be added via the i_ref1 function argument to either feols() and fepois().\n\n\nNew feature\nA dids2() function is added, which implements the 2-stage difference-in-differences procedure à la Gardner and follows the syntax of @kylebutts did2s R package.\nfrom pyfixest.did.did import did2s\nfrom pyfixest.estimation import feols\nfrom pyfixest.visualize import iplot\nimport pandas as pd\nimport numpy as np\n\ndf_het = pd.read_csv(\"https://raw.githubusercontent.com/py-econometrics/pyfixest/master/pyfixest/did/data/df_het.csv\")\n\nfit = did2s(\n    df_het,\n    yname = \"dep_var\",\n    first_stage = \"~ 0 | state + year\",\n    second_stage = \"~i(rel_year)\",\n    treatment = \"treat\",\n    cluster = \"state\",\n    i_ref1 = [-1.0, np.inf],\n)\n\nfit_twfe = feols(\n    \"dep_var ~ i(rel_year) | state + year\",\n    df_het,\n    i_ref1 = [-1.0, np.inf]\n)\n\niplot([fit, fit_twfe], coord_flip=False, figsize = (900, 400), title = \"TWFE vs DID2S\")"
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.7",
    "href": "changelog.html#pyfixest-0.10.7",
    "title": "Changelog",
    "section": "PyFixest 0.10.7",
    "text": "PyFixest 0.10.7\n\nAdds basic support for event study estimation via two-way fixed effects and Gardner’s two-stage “Did2s” approach. This is a beta version and experimental. Further updates (i.e. proper event studies vs “only” ATTs) and a more flexible did2s front end will follow in future releases.\n\n%load_ext autoreload\n%autoreload 2\n\nfrom pyfixest.did.did import event_study\nimport pyfixest as pf\nimport pandas as pd\ndf_het = pd.read_csv(\"pyfixest/did/data/df_het.csv\")\n\nfit_twfe = event_study(\n    data = df_het,\n    yname = \"dep_var\",\n    idname= \"state\",\n    tname = \"year\",\n    gname = \"g\",\n    estimator = \"twfe\"\n)\n\nfit_did2s = event_study(\n    data = df_het,\n    yname = \"dep_var\",\n    idname= \"state\",\n    tname = \"year\",\n    gname = \"g\",\n    estimator = \"did2s\"\n)\n\npf.etable([fit_twfe, fit_did2s])\n# | Coefficient   | est1             | est2             |\n# |:--------------|:-----------------|:-----------------|\n# | ATT           | 2.135*** (0.044) | 2.152*** (0.048) |\n# Significance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001"
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.6",
    "href": "changelog.html#pyfixest-0.10.6",
    "title": "Changelog",
    "section": "PyFixest 0.10.6",
    "text": "PyFixest 0.10.6\n\nAdds an etable() function that outputs markdown, latex or a pd.DataFrame."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.5",
    "href": "changelog.html#pyfixest-0.10.5",
    "title": "Changelog",
    "section": "PyFixest 0.10.5",
    "text": "PyFixest 0.10.5\n\nFixes a big in IV estimation that would trigger an error. See here for details. Thanks to @aeturrell for reporting!"
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.4",
    "href": "changelog.html#pyfixest-0.10.4",
    "title": "Changelog",
    "section": "PyFixest 0.10.4",
    "text": "PyFixest 0.10.4\n\nImplements a custom function to drop singleton fixed effects.\nAdditional small performance improvements."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.3",
    "href": "changelog.html#pyfixest-0.10.3",
    "title": "Changelog",
    "section": "PyFixest 0.10.3",
    "text": "PyFixest 0.10.3\n\nAllows for white space in the multiway clustering formula.\nAdds documentation for multiway clustering."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.2",
    "href": "changelog.html#pyfixest-0.10.2",
    "title": "Changelog",
    "section": "PyFixest 0.10.2",
    "text": "PyFixest 0.10.2\n\nAdds support for two-way clustering.\nAdds support for CRV3 inference for Poisson regression."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10.1",
    "href": "changelog.html#pyfixest-0.10.1",
    "title": "Changelog",
    "section": "PyFixest 0.10.1",
    "text": "PyFixest 0.10.1\n\nAdapts the internal fixed effects demeaning criteron to match `PyHDFE’s default.\nAdds Styfen as coauthor."
  },
  {
    "objectID": "changelog.html#pyfixest-0.10",
    "href": "changelog.html#pyfixest-0.10",
    "title": "Changelog",
    "section": "PyFixest 0.10",
    "text": "PyFixest 0.10\n\nMultiple performance improvements.\nMost importantly, implements a custom demeaning algorithm in numba - thanks to Styfen Schaer (@styfenschaer), which leads to performance improvements of 5x or more:\n\n%load_ext autoreload\n%autoreload 2\n\nimport numpy as np\nimport time\nimport pyhdfe\nfrom pyfixest.demean import demean\n\nnp.random.seed(1238)\nN = 10_000_000\nx = np.random.normal(0, 1, 10*N).reshape((N,10))\nf1 = np.random.choice(list(range(1000)), N).reshape((N,1))\nf2 = np.random.choice(list(range(1000)), N).reshape((N,1))\n\nflist = np.concatenate((f1, f2), axis = 1)\nweights = np.ones(N)\n\nalgorithm = pyhdfe.create(flist)\n\nstart_time = time.time()\nres_pyhdfe = algorithm.residualize(x)\nend_time = time.time()\nprint(end_time - start_time)\n# 26.04527711868286\n\n\nstart_time = time.time()\nres_pyfixest, success = demean(x, flist, weights, tol = 1e-10)\n# Calculate the execution time\nend_time = time.time()\nprint(end_time - start_time)\n#4.334428071975708\n\nnp.allclose(res_pyhdfe , res_pyfixest)\n# True"
  },
  {
    "objectID": "changelog.html#pyfixest-0.9.11",
    "href": "changelog.html#pyfixest-0.9.11",
    "title": "Changelog",
    "section": "PyFixest 0.9.11",
    "text": "PyFixest 0.9.11\n\nBump required formulaic version to 0.6.5.\nStop copying the data frame in fixef()."
  },
  {
    "objectID": "changelog.html#pyfixest-0.9.10",
    "href": "changelog.html#pyfixest-0.9.10",
    "title": "Changelog",
    "section": "PyFixest 0.9.10",
    "text": "PyFixest 0.9.10\n\nFixes a big in the wildboottest method (see #158).\nAllows to run a wild bootstrap after fixed effect estimation."
  },
  {
    "objectID": "changelog.html#pyfixest-0.9.9",
    "href": "changelog.html#pyfixest-0.9.9",
    "title": "Changelog",
    "section": "PyFixest 0.9.9",
    "text": "PyFixest 0.9.9\n\nAdds support for wildboottest for Python 3.11."
  },
  {
    "objectID": "changelog.html#pyfixest-0.9.8",
    "href": "changelog.html#pyfixest-0.9.8",
    "title": "Changelog",
    "section": "PyFixest 0.9.8",
    "text": "PyFixest 0.9.8\n\nFixes a couple more bugs in the predict() and fixef() methods.\nThe predict() argument data is renamed to newdata."
  },
  {
    "objectID": "changelog.html#pyfixest-0.9.7",
    "href": "changelog.html#pyfixest-0.9.7",
    "title": "Changelog",
    "section": "PyFixest 0.9.7",
    "text": "PyFixest 0.9.7\nFixes a bug in predict() produced when multicollinear variables are dropped."
  },
  {
    "objectID": "changelog.html#pyfixest-0.9.6",
    "href": "changelog.html#pyfixest-0.9.6",
    "title": "Changelog",
    "section": "PyFixest 0.9.6",
    "text": "PyFixest 0.9.6\nImproved Collinearity handling. See #145"
  },
  {
    "objectID": "changelog.html#pyfixest-0.9.5",
    "href": "changelog.html#pyfixest-0.9.5",
    "title": "Changelog",
    "section": "PyFixest 0.9.5",
    "text": "PyFixest 0.9.5\n\nMoves plotting from matplotlib to lets-plot.\nFixes a few minor bugs in plotting and the fixef() method."
  },
  {
    "objectID": "changelog.html#pyfixest-0.9.1",
    "href": "changelog.html#pyfixest-0.9.1",
    "title": "Changelog",
    "section": "PyFixest 0.9.1",
    "text": "PyFixest 0.9.1\n\nBreaking API changes\nIt is no longer required to initiate an object of type Fixest prior to running [Feols(/reference/Feols.qmd) or fepois. Instead, you can now simply use feols() and fepois() as functions, just as in fixest. Both function can be found in an estimation module and need to obtain a pd.DataFrame as a function argument:\nfrom pyfixest.estimation import fixest, fepois\nfrom pyfixest.utils import get_data\n\ndata = get_data()\nfit = feols(\"Y ~ X1 | f1\", data = data, vcov = \"iid\")\nCalling feols() will return an instance of class [Feols(/reference/Feols.qmd), while calling fepois() will return an instance of class Fepois. Multiple estimation syntax will return an instance of class FixestMulti.\nPost processing works as before via .summary(), .tidy() and other methods.\n\n\nNew Features\nA summary function allows to compare multiple models:\nfrom pyfixest.summarize import summary\nfit2 = feols(\"Y ~ X1 + X2| f1\", data = data, vcov = \"iid\")\nsummary([fit, fit2])\nVisualization is possible via custom methods (.iplot() & .coefplot()), but a new module allows to visualize a list of [Feols(/reference/Feols.qmd) and/or Fepois instances:\nfrom pyfixest.visualize import coefplot, iplot\ncoefplot([fit, fit2])\nThe documentation has been improved (though there is still room for progress), and the code has been cleaned up a bit (also lots of room for improvements)."
  },
  {
    "objectID": "contributing.html",
    "href": "contributing.html",
    "title": "Contributing",
    "section": "",
    "text": "Thanks for showing interest in contributing to pyfixest! We appreciate all contributions and constructive feedback, whether that be reporting bugs, requesting new features, or suggesting improvements to documentation.\nIf you’d like to get involved, but are not yet sure how, please feel free to send us an email. Some familiarity with either Python or econometrics will help, but you really don’t need to be a numpy core developer or have published in Econometrica =) We’d be more than happy to invest time to help you get started!"
  },
  {
    "objectID": "contributing.html#overview",
    "href": "contributing.html#overview",
    "title": "Contributing",
    "section": "",
    "text": "Thanks for showing interest in contributing to pyfixest! We appreciate all contributions and constructive feedback, whether that be reporting bugs, requesting new features, or suggesting improvements to documentation.\nIf you’d like to get involved, but are not yet sure how, please feel free to send us an email. Some familiarity with either Python or econometrics will help, but you really don’t need to be a numpy core developer or have published in Econometrica =) We’d be more than happy to invest time to help you get started!"
  },
  {
    "objectID": "contributing.html#reporting-bugs",
    "href": "contributing.html#reporting-bugs",
    "title": "Contributing",
    "section": "Reporting bugs",
    "text": "Reporting bugs\nWe use GitHub issues to track bugs. You can report a bug by opening a new issue or contribute to an existing issue if related to the bug you are reporting.\nBefore creating a bug report, please check that your bug has not already been reported, and that your bug exists on the latest version of pyfixest. If you find a closed issue that seems to report the same bug you’re experiencing, open a new issue and include a link to the original issue in your issue description.\nPlease include as many details as possible in your bug report. The information helps the maintainers resolve the issue faster."
  },
  {
    "objectID": "contributing.html#suggesting-enhancements",
    "href": "contributing.html#suggesting-enhancements",
    "title": "Contributing",
    "section": "Suggesting enhancements",
    "text": "Suggesting enhancements\nWe use GitHub issues to track bugs and suggested enhancements. You can suggest an enhancement by opening a new feature request. Before creating an enhancement suggestion, please check that a similar issue does not already exist.\nPlease describe the behavior you want and why, and provide examples of how pyfixest would be used if your feature were added."
  },
  {
    "objectID": "contributing.html#contributing-to-the-codebase",
    "href": "contributing.html#contributing-to-the-codebase",
    "title": "Contributing",
    "section": "Contributing to the codebase",
    "text": "Contributing to the codebase\n\nSetting up your local environment\nWould you like to contribute to pyfixest, or run some of the unit tests locally? Awesome! Here’s how you can get started:\nFirst, you’ll want to fork the pyfixest GitHub repository. Then, clone your forked repo with git:\ngit clone https://github.com/&lt;username&gt;/pyfixest.git\ncd pyfixest\nTo work on pyfixest, you’ll need Python and R installed. If you’re planning to work on the documentation, be sure to have Quarto installed as well. Note: an R installation is only needed if you plan to run the unit tests locally.\nFor guidance on installing R and Python, check out the sections below.\n\n\nPackage Management via pixi\nPyFixest is using pixi.\nTo install pixi, just follow the installation instructions from the pixi documentation.\nOnce pixi is installed, you can initialize the project environment and install all dependencies with\ncd path-to-pyfixest\npixi install\nAfter installation, you can activate a custom pixi environment for pyfixest by typing:\npixi shell\nYou’ll now be in the pixi environment and ready to go!\nFor most development tasks, it’s best to activate the development environment since it includes all the necessary dependencies for development.\npixi shell --environment dev    # open the dev environment\n\n\nPixi tasks\nTo help with development, we’ve included several handy pixi tasks.\nFor example, we use ruff and pre-commit to ensure code consistency across the project.\nTo install the required hooks, simply run\npixi run lint\nand you’re ready to go! After installation, the task will run all linting rules via ruff.\nWe’ve included other tasks to help install the necessary R packages for running unit tests or to run different sets of tests:\n# install all R development dependencies\npixi run install-r\n# run all tests via pytest\npixi run tests\n# run all tests excluding very computationally demanding tests\npixi run tests-regular\n# rerun failed tests\npixi run tests-rerun\nBuilding the documentation is also straightforward. We’ve got tasks to build, render, and preview the docs:\n# Build documentation and website\npixi run docs-build\n# render the docs\npixi run docs-render\n# preview the docs\npixi run docs-preview\nKeep in mind that you’ll need quarto installed to build the documentation locally."
  },
  {
    "objectID": "contributing.html#installing-python-r-and-quarto",
    "href": "contributing.html#installing-python-r-and-quarto",
    "title": "Contributing",
    "section": "Installing Python, R and Quarto",
    "text": "Installing Python, R and Quarto\n\nInstalling Python\nThe minimal Python version to develop pyfixest is 3.9. You can installed it on Mac/Linux via Hombrew:\nbrew install python@3.11 # specify the version of python you prefer\nOn Windows via Winget:\nwinget install -e --id Python.Python.3.11\n\n\nInstalling R\nNote that installing R and the R packages listed below is only necessary if you want to test against R in your local installation. You can also test against R by using github actions.\nOn Mac/Linux:\nbrew install r\nDepending on your local set up, you may need to install additional libraries, for example:\nsudo apt install gcc-11 cmake\nOn Windows using Winget:\nwinget install -e --id RProject.R\n\n\nInstalling Quarto\nDocumentation for pyfixest is written, compiled, and published using Quarto.\nTo install Quarto, run:\nOn MacOS via Homebrew:\nbrew install --cask quarto\nOn Linux (Ubuntu using gdebi):\nsudo curl -o quarto-linux-amd64.deb -L &lt;https://github.com/quarto-dev/quarto-cli/releases/download/v${QUARTO_VERSION}/quarto-${QUARTO_VERSION}-linux-amd64.deb&gt;\nsudo gdebi quarto-linux-amd64.deb\nOn Windows:\nscoop bucket add extras\nscoop install extras/quarto"
  },
  {
    "objectID": "marginaleffects.html",
    "href": "marginaleffects.html",
    "title": "Marginal Effects and Hypothesis Tests via marginaleffects",
    "section": "",
    "text": "We can compute marginal effects and linear and non-linear hypothesis tests via the excellent marginaleffects package.\nfrom marginaleffects import hypotheses\n\nimport pyfixest as pf\n\ndata = pf.get_data()\nfit = pf.feols(\"Y ~ X1 + X2\", data=data)\n\nfit.tidy()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nIntercept\n0.888779\n0.108422\n8.197374\n8.881784e-16\n0.676016\n1.101542\n\n\nX1\n-0.992936\n0.082117\n-12.091650\n0.000000e+00\n-1.154079\n-0.831792\n\n\nX2\n-0.176342\n0.021766\n-8.101743\n1.554312e-15\n-0.219055\n-0.133630\nSuppose we were interested in testing the hypothesis that \\(X_{1} = X_{2}\\). Given the relatively large differences in coefficients and small standard errors, we will likely reject the null that the two parameters are equal.\nWe can run the formal test via the hypotheses function from the marginaleffects package.\nhypotheses(fit, \"X1 - X2 = 0\")\n\n\nshape: (1, 8)\n\n\n\nterm\nestimate\nstd_error\nstatistic\np_value\ns_value\nconf_low\nconf_high\n\n\nstr\nf64\nf64\nf64\nf64\nf64\nf64\nf64\n\n\n\n\n\"X1-X2=0\"\n-0.816593\n0.085179\n-9.586797\n0.0\ninf\n-0.983541\n-0.649646\nAnd indeed, we reject the null of equality of coefficients: we get a p-value of zero and a confidence interval that does not contain 0."
  },
  {
    "objectID": "marginaleffects.html#non-linear-hypothesis-tests-ratio-estimates",
    "href": "marginaleffects.html#non-linear-hypothesis-tests-ratio-estimates",
    "title": "Marginal Effects and Hypothesis Tests via marginaleffects",
    "section": "Non-Linear Hypothesis Tests: Ratio Estimates",
    "text": "Non-Linear Hypothesis Tests: Ratio Estimates\nWe can also test run-linear hypotheses, in which case marginaleffects will automatically compute correct standard errors based on the estimated covariance matrix and the Delta method. This is for example useful for computing inferential statistics for the “relative uplift” in an AB test.\nFor the moment, let’s assume that \\(X1\\) is a randomly assigned treatment variable. As before, \\(Y\\) is our variable / KPI of interest.\nUnder randomization, the model intercept measures the “baseline”, i.e. the population average of \\(Y\\) in the absence of treatment. To compute a relative uplift, we might compute\n\n(fit.coef().xs(\"X1\") / fit.coef().xs(\"Intercept\") - 1) * 100\n\nnp.float64(-211.71906665561212)\n\n\nSo we have a really big negative treatment effect of around minus 212%! To conduct correct inference on this ratio statistic, we need to use the delta method.\n\nThe Multivariate Delta Method\nIn a nutshell, the delta method provides a way to approximate the asympotic distribution of any non-linear transformation \\(g()\\) or one or more random variables.\nIn the case of the ratio statistics, this non-linear transformation can be denoted as \\(g(\\theta_{1}, \\theta_{2}) = \\theta_{1} / \\theta_{2}\\).\nHere’s the Delta Method theorem:\nFirst, we define \\(\\theta = (\\theta_{1}, \\theta_{2})'\\) and \\(\\mu = (\\mu_{1}, \\mu_{2})'\\).\nBy the law of large numbers, we know that\n\\[\n\\sqrt{N} (\\theta - \\mu) \\rightarrow_{d} N(0_{2}, \\Sigma_{2,2}) \\text{ if } N \\rightarrow \\infty.\n\\]\nBy the Delta Method, we can then approximate the limit distribution of \\(g(\\theta)\\) as\n\\[\n\\sqrt{N}  (g(\\theta) - g(\\mu)) \\rightarrow_{d} N(0_{1}, g'(\\theta) \\times \\Sigma \\times g(\\theta)) \\text{ if } N \\rightarrow \\infty.\n\\].\nHere’s a long derivation of how to use the the delta method for inference of ratio statistics.. The key steps from the formula above is to derive the expression for the asymptotic variance $ g’() g()$.\nBut hey - we’re lucky, because marginaleffects will do all this work for us: we don’t have to derive analytic gradients ourselves =)\n\n\nUsing the Delta Method via marginaleffects:\nWe can employ the Delta Method via marginaleffects via the hypotheses function:\n\nhypotheses(fit, \"(X1 / Intercept - 1) * 100 = 0\")\n\n\nshape: (1, 8)\n\n\n\nterm\nestimate\nstd_error\nstatistic\np_value\ns_value\nconf_low\nconf_high\n\n\nstr\nf64\nf64\nf64\nf64\nf64\nf64\nf64\n\n\n\n\n\"(X1/Intercept-1)*100=0\"\n-211.719067\n8.478682\n-24.970751\n0.0\ninf\n-228.336979\n-195.101155\n\n\n\n\n\n\nAs before, we get an estimate of around -212%. Additionally, we obtain a 95% CI via the Delta Method of [-228%, -195%].\nBesides hypopotheses testing, you can do a range of other cool things with the marginaleffects package. For example (and likely unsurprisingly), you can easily compute all sorts of marginal effects for your regression models. For all the details, we highly recommend to take a look at the marginaleffects zoo book!."
  },
  {
    "objectID": "pyfixest.html#features",
    "href": "pyfixest.html#features",
    "title": "PyFixest: Fast High-Dimensional Fixed Effects Regression in Python",
    "section": "Features",
    "text": "Features\n\nOLS, WLS and IV Regression with Fixed-Effects Demeaning via Frisch-Waugh-Lovell\nPoisson Regression following the pplmhdfe algorithm\nMultiple Estimation Syntax\nProbit, Logit and Gaussian Family GLMs (currently without fixed effects demeaning, this is WIP)\nSeveral Robust and Cluster Robust Variance-Covariance Estimators\nWild Cluster Bootstrap Inference (via wildboottest)\nDifference-in-Differences Estimators:\n\nThe canonical Two-Way Fixed Effects Estimator\nGardner’s two-stage (“Did2s”) estimator\nBasic Versions of the Local Projections estimator following Dube et al (2023)\n\nMultiple Hypothesis Corrections following the Procedure by Romano and Wolf and Simultaneous Confidence Intervals using a Multiplier Bootstrap\nThe Causal Cluster Variance Estimator (CCV) following Abadie et al.\nRegression Decomposition following Gelbach (2016)\nPublication-ready tables with Great Tables or LaTex booktabs"
  },
  {
    "objectID": "pyfixest.html#installation",
    "href": "pyfixest.html#installation",
    "title": "PyFixest: Fast High-Dimensional Fixed Effects Regression in Python",
    "section": "Installation",
    "text": "Installation\nYou can install the release version from PyPi by running\npip install -U pyfixest\nor the development version from github by running\npip install git+https://github.com/py-econometrics/pyfixest.git"
  },
  {
    "objectID": "pyfixest.html#benchmarks",
    "href": "pyfixest.html#benchmarks",
    "title": "PyFixest: Fast High-Dimensional Fixed Effects Regression in Python",
    "section": "Benchmarks",
    "text": "Benchmarks\nAll benchmarks follow the fixest benchmarks. All non-pyfixest timings are taken from the fixest benchmarks."
  },
  {
    "objectID": "pyfixest.html#quickstart",
    "href": "pyfixest.html#quickstart",
    "title": "PyFixest: Fast High-Dimensional Fixed Effects Regression in Python",
    "section": "Quickstart",
    "text": "Quickstart\nimport pyfixest as pf\n\ndata = pf.get_data()\npf.feols(\"Y ~ X1 | f1 + f2\", data=data).summary()\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: f1+f2\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.919 |        0.065 |   -14.057 |      0.000 | -1.053 |  -0.786 |\n---\nRMSE: 1.441   R2: 0.609   R2 Within: 0.2\n\nMultiple Estimation\nYou can estimate multiple models at once by using multiple estimation syntax:\n# OLS Estimation: estimate multiple models at once\nfit = pf.feols(\"Y + Y2 ~X1 | csw0(f1, f2)\", data = data, vcov = {'CRV1':'group_id'})\n# Print the results\nfit.etable()\n                           est1               est2               est3               est4               est5               est6\n------------  -----------------  -----------------  -----------------  -----------------  -----------------  -----------------\ndepvar                        Y                 Y2                  Y                 Y2                  Y                 Y2\n------------------------------------------------------------------------------------------------------------------------------\nIntercept      0.919*** (0.121)   1.064*** (0.232)\nX1            -1.000*** (0.117)  -1.322*** (0.211)  -0.949*** (0.087)  -1.266*** (0.212)  -0.919*** (0.069)  -1.228*** (0.194)\n------------------------------------------------------------------------------------------------------------------------------\nf2                            -                  -                  -                  -                  x                  x\nf1                            -                  -                  x                  x                  x                  x\n------------------------------------------------------------------------------------------------------------------------------\nR2                        0.123              0.037              0.437              0.115              0.609              0.168\nS.E. type          by: group_id       by: group_id       by: group_id       by: group_id       by: group_id       by: group_id\nObservations                998                999                997                998                997                998\n------------------------------------------------------------------------------------------------------------------------------\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001\nFormat of coefficient cell:\nCoefficient (Std. Error)\n\n\nAdjust Standard Errors “on-the-fly”\nStandard Errors can be adjusted after estimation, “on-the-fly”:\nfit1 = fit.fetch_model(0)\nfit1.vcov(\"hetero\").summary()\nModel:  Y~X1\n###\n\nEstimation:  OLS\nDep. var.: Y\nInference:  hetero\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept     |      0.919 |        0.112 |     8.223 |      0.000 |  0.699 |   1.138 |\n| X1            |     -1.000 |        0.082 |   -12.134 |      0.000 | -1.162 |  -0.838 |\n---\nRMSE: 2.158   R2: 0.123\n\n\nPoisson Regression via fepois()\nYou can estimate Poisson Regressions via the fepois() function:\npoisson_data = pf.get_data(model = \"Fepois\")\npf.fepois(\"Y ~ X1 + X2 | f1 + f2\", data = poisson_data).summary()\n###\n\nEstimation:  Poisson\nDep. var.: Y, Fixed effects: f1+f2\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.007 |        0.035 |    -0.190 |      0.850 | -0.075 |   0.062 |\n| X2            |     -0.015 |        0.010 |    -1.449 |      0.147 | -0.035 |   0.005 |\n---\nDeviance: 1068.169\n\n\nIV Estimation via three-part formulas\nLast, PyFixest also supports IV estimation via three part formula syntax:\nfit_iv = pf.feols(\"Y ~ 1 | f1 | X1 ~ Z1\", data = data)\nfit_iv.summary()\n###\n\nEstimation:  IV\nDep. var.: Y, Fixed effects: f1\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -1.025 |        0.115 |    -8.930 |      0.000 | -1.259 |  -0.790 |\n---"
  },
  {
    "objectID": "pyfixest.html#call-for-contributions",
    "href": "pyfixest.html#call-for-contributions",
    "title": "PyFixest: Fast High-Dimensional Fixed Effects Regression in Python",
    "section": "Call for Contributions",
    "text": "Call for Contributions\nThanks for showing interest in contributing to pyfixest! We appreciate all contributions and constructive feedback, whether that be reporting bugs, requesting new features, or suggesting improvements to documentation.\nIf you’d like to get involved, but are not yet sure how, please feel free to send us an email. Some familiarity with either Python or econometrics will help, but you really don’t need to be a numpy core developer or have published in Econometrica =) We’d be more than happy to invest time to help you get started!"
  },
  {
    "objectID": "pyfixest.html#contributors",
    "href": "pyfixest.html#contributors",
    "title": "PyFixest: Fast High-Dimensional Fixed Effects Regression in Python",
    "section": "Contributors ✨",
    "text": "Contributors ✨\nThanks goes to these wonderful people:\n\n\n\n\n\n\n\nstyfenschaer💻\n\n\nNiall Keleher🚇 💻\n\n\nWenzhi Ding💻\n\n\nApoorva Lal💻 🐛\n\n\nJuan Orduz🚇 💻\n\n\nAlexander Fischer💻 🚇\n\n\naeturrell✅ 📖 📣\n\n\n\n\n\n\n\nThis project follows the all-contributors specification. Contributions of any kind welcome!"
  },
  {
    "objectID": "quickstart.html",
    "href": "quickstart.html",
    "title": "Getting Started with PyFixest",
    "section": "",
    "text": "A fixed effect model is a statistical model that includes fixed effects, which are parameters that are estimated to be constant across different groups.\nExample [Panel Data]: In the context of panel data, fixed effects are parameters that are constant across different individuals or time. The typical model example is given by the following equation:\n\\[\nY_{it} = \\beta X_{it} + \\alpha_i + \\psi_t + \\varepsilon_{it}\n\\]\nwhere \\(Y_{it}\\) is the dependent variable for individual \\(i\\) at time \\(t\\), \\(X_{it}\\) is the independent variable, \\(\\beta\\) is the coefficient of the independent variable, \\(\\alpha_i\\) is the individual fixed effect, \\(\\psi_t\\) is the time fixed effect, and \\(\\varepsilon_{it}\\) is the error term. The individual fixed effect \\(\\alpha_i\\) is a parameter that is constant across time for each individual, while the time fixed effect \\(\\psi_t\\) is a parameter that is constant across individuals for each time period.\nNote however that, despite the fact that fixed effects are commonly used in panel setting, one does not need a panel data set to work with fixed effects. For example, cluster randomized trials with cluster fixed effects, or wage regressions with worker and firm fixed effects.\nIn this “quick start” guide, we will show you how to estimate a fixed effect model using the PyFixest package. We do not go into the details of the theory behind fixed effect models, but we focus on how to estimate them using PyFixest.\n\n\n\nIn a first step, we load the module and some synthetic example data:\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import LetsPlot\nfrom marginaleffects import slopes, avg_slopes\n\nimport pyfixest as pf\n\nLetsPlot.setup_html()\n\nplt.style.use(\"seaborn-v0_8\")\n\n%load_ext watermark\n%config InlineBackend.figure_format = \"retina\"\n%watermark --iversions\n\ndata = pf.get_data()\n\ndata.head()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\npandas    : 2.2.3\nmatplotlib: 3.10.0\npyfixest  : 0.27.0\nnumpy     : 2.0.2\n\n\n\n\n\n\n\n\n\n\nY\nY2\nX1\nX2\nf1\nf2\nf3\ngroup_id\nZ1\nZ2\nweights\n\n\n\n\n0\nNaN\n2.357103\n0.0\n0.457858\n15.0\n0.0\n7.0\n9.0\n-0.330607\n1.054826\n0.661478\n\n\n1\n-1.458643\n5.163147\nNaN\n-4.998406\n6.0\n21.0\n4.0\n8.0\nNaN\n-4.113690\n0.772732\n\n\n2\n0.169132\n0.751140\n2.0\n1.558480\nNaN\n1.0\n7.0\n16.0\n1.207778\n0.465282\n0.990929\n\n\n3\n3.319513\n-2.656368\n1.0\n1.560402\n1.0\n10.0\n11.0\n3.0\n2.869997\n0.467570\n0.021123\n\n\n4\n0.134420\n-1.866416\n2.0\n-3.472232\n19.0\n20.0\n6.0\n14.0\n0.835819\n-3.115669\n0.790815\n\n\n\n\n\n\n\n\ndata.info()\n\n&lt;class 'pandas.core.frame.DataFrame'&gt;\nRangeIndex: 1000 entries, 0 to 999\nData columns (total 11 columns):\n #   Column    Non-Null Count  Dtype  \n---  ------    --------------  -----  \n 0   Y         999 non-null    float64\n 1   Y2        1000 non-null   float64\n 2   X1        999 non-null    float64\n 3   X2        1000 non-null   float64\n 4   f1        999 non-null    float64\n 5   f2        1000 non-null   float64\n 6   f3        1000 non-null   float64\n 7   group_id  1000 non-null   float64\n 8   Z1        999 non-null    float64\n 9   Z2        1000 non-null   float64\n 10  weights   1000 non-null   float64\ndtypes: float64(11)\nmemory usage: 86.1 KB\n\n\nWe see that some of our columns have missing data.\n\n\n\nWe are interested in the relation between the dependent variable Y and the independent variables X1 using a fixed effect model for group_id. Let’s see how the data looks like:\n\nax = data.plot(kind=\"scatter\", x=\"X1\", y=\"Y\", c=\"group_id\", colormap=\"viridis\")\n\n\n\n\n\n\n\n\nWe can estimate a fixed effects regression via the feols() function. feols() has three arguments: a two-sided model formula, the data, and optionally, the type of inference.\n\nfit = pf.feols(fml=\"Y ~ X1 | group_id\", data=data, vcov=\"HC1\")\ntype(fit)\n\npyfixest.estimation.feols_.Feols\n\n\nThe first part of the formula contains the dependent variable and “regular” covariates, while the second part contains fixed effects.\nfeols() returns an instance of the Fixest class.\n\n\n\nTo inspect the results, we can use a summary function or method:\n\nfit.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: group_id\nInference:  HC1\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -1.019 |        0.082 |   -12.352 |      0.000 | -1.181 |  -0.857 |\n---\nRMSE: 2.141 R2: 0.137 R2 Within: 0.126 \n\n\nOr display a formatted regression table:\n\npf.etable(fit)\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n\n\n\n\ncoef\n\n\nX1\n-1.019***\n(0.082)\n\n\nfe\n\n\ngroup_id\nx\n\n\nstats\n\n\nObservations\n998\n\n\nS.E. type\nhetero\n\n\nR2\n0.137\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nAlternatively, the .summarize module contains a summary function, which can be applied on instances of regression model objects or lists of regression model objects. For details on how to customize etable(), please take a look at the dedicated vignette.\n\npf.summary(fit)\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: group_id\nInference:  HC1\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -1.019 |        0.082 |   -12.352 |      0.000 | -1.181 |  -0.857 |\n---\nRMSE: 2.141 R2: 0.137 R2 Within: 0.126 \n\n\nYou can access individual elements of the summary via dedicated methods: .tidy() returns a “tidy” pd.DataFrame, .coef() returns estimated parameters, and se() estimated standard errors. Other methods include pvalue(), confint() and tstat().\n\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n-1.019009\n0.082498\n-12.351897\n0.0\n-1.180898\n-0.857119\n\n\n\n\n\n\n\n\nfit.coef()\n\nCoefficient\nX1   -1.019009\nName: Estimate, dtype: float64\n\n\n\nfit.se()\n\nCoefficient\nX1    0.082498\nName: Std. Error, dtype: float64\n\n\n\nfit.tstat()\n\nCoefficient\nX1   -12.351897\nName: t value, dtype: float64\n\n\n\nfit.confint()\n\n\n\n\n\n\n\n\n2.5%\n97.5%\n\n\n\n\nX1\n-1.180898\n-0.857119\n\n\n\n\n\n\n\nLast, model results can be visualized via dedicated methods for plotting:\n\nfit.coefplot()\n# or pf.coefplot([fit])\n\n   \n   \n\n\n\n\n\nLet’s have a quick d-tour on the intuition behind fixed effects models using the example above. To do so, let us begin by comparing it with a simple OLS model.\n\nfit_simple = pf.feols(\"Y ~ X1\", data=data, vcov=\"HC1\")\n\nfit_simple.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: 0\nInference:  HC1\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept     |      0.919 |        0.112 |     8.223 |      0.000 |  0.699 |   1.138 |\n| X1            |     -1.000 |        0.082 |   -12.134 |      0.000 | -1.162 |  -0.838 |\n---\nRMSE: 2.158 R2: 0.123 \n\n\nWe can compare both models side by side in a regression table:\n\npf.etable([fit, fit_simple])\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n\n\n\n\ncoef\n\n\nX1\n-1.019***\n(0.082)\n-1.000***\n(0.082)\n\n\nIntercept\n\n0.919***\n(0.112)\n\n\nfe\n\n\ngroup_id\nx\n-\n\n\nstats\n\n\nObservations\n998\n998\n\n\nS.E. type\nhetero\nhetero\n\n\nR2\n0.137\n0.123\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe see that the X1 coefficient is -1.019, which is less than the value from the OLS model in column (2). Where is the difference coming from? Well, in the fixed effect model we are interested in controlling for the feature group_id. One possibility to do this is by adding a simple dummy variable for each level of group_id.\n\nfit_dummy = pf.feols(\"Y ~ X1 + C(group_id) \", data=data, vcov=\"HC1\")\n\nfit_dummy.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: 0\nInference:  HC1\nObservations:  998\n\n| Coefficient         |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept           |      0.760 |        0.288 |     2.640 |      0.008 |  0.195 |   1.326 |\n| X1                  |     -1.019 |        0.083 |   -12.234 |      0.000 | -1.182 |  -0.856 |\n| C(group_id)[T.1.0]  |      0.380 |        0.451 |     0.844 |      0.399 | -0.504 |   1.264 |\n| C(group_id)[T.2.0]  |      0.084 |        0.389 |     0.216 |      0.829 | -0.680 |   0.848 |\n| C(group_id)[T.3.0]  |      0.790 |        0.415 |     1.904 |      0.057 | -0.024 |   1.604 |\n| C(group_id)[T.4.0]  |     -0.189 |        0.388 |    -0.487 |      0.626 | -0.950 |   0.572 |\n| C(group_id)[T.5.0]  |      0.537 |        0.388 |     1.385 |      0.166 | -0.224 |   1.297 |\n| C(group_id)[T.6.0]  |      0.307 |        0.398 |     0.771 |      0.441 | -0.474 |   1.087 |\n| C(group_id)[T.7.0]  |      0.015 |        0.422 |     0.035 |      0.972 | -0.814 |   0.844 |\n| C(group_id)[T.8.0]  |      0.382 |        0.406 |     0.941 |      0.347 | -0.415 |   1.179 |\n| C(group_id)[T.9.0]  |      0.219 |        0.417 |     0.526 |      0.599 | -0.599 |   1.037 |\n| C(group_id)[T.10.0] |     -0.363 |        0.422 |    -0.861 |      0.390 | -1.191 |   0.465 |\n| C(group_id)[T.11.0] |      0.201 |        0.387 |     0.520 |      0.603 | -0.559 |   0.961 |\n| C(group_id)[T.12.0] |     -0.110 |        0.410 |    -0.268 |      0.788 | -0.915 |   0.694 |\n| C(group_id)[T.13.0] |      0.126 |        0.440 |     0.287 |      0.774 | -0.736 |   0.989 |\n| C(group_id)[T.14.0] |      0.353 |        0.416 |     0.848 |      0.397 | -0.464 |   1.170 |\n| C(group_id)[T.15.0] |      0.469 |        0.398 |     1.179 |      0.239 | -0.312 |   1.249 |\n| C(group_id)[T.16.0] |     -0.135 |        0.396 |    -0.340 |      0.734 | -0.913 |   0.643 |\n| C(group_id)[T.17.0] |     -0.005 |        0.401 |    -0.013 |      0.989 | -0.792 |   0.781 |\n| C(group_id)[T.18.0] |      0.283 |        0.403 |     0.702 |      0.483 | -0.508 |   1.074 |\n---\nRMSE: 2.141 R2: 0.137 \n\n\nThis is does not scale well! Imagine you have 1000 different levels of group_id. You would need to add 1000 dummy variables to your model. This is where fixed effect models come in handy. They allow you to control for these fixed effects without adding all these dummy variables. The way to do it is by a demeaning procedure. The idea is to subtract the average value of each level of group_id from the respective observations. This way, we control for the fixed effects without adding all these dummy variables. Let’s try to do this manually:\n\ndef _demean_column(df: pd.DataFrame, column: str, by: str) -&gt; pd.Series:\n    return df[column] - df.groupby(by)[column].transform(\"mean\")\n\n\nfit_demeaned = pf.feols(\n    fml=\"Y_demeaned ~ X1_demeaned\",\n    data=data.assign(\n        Y_demeaned=lambda df: _demean_column(df, \"Y\", \"group_id\"),\n        X1_demeaned=lambda df: _demean_column(df, \"X1\", \"group_id\"),\n    ),\n    vcov=\"HC1\",\n)\n\nfit_demeaned.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y_demeaned, Fixed effects: 0\nInference:  HC1\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept     |      0.003 |        0.068 |     0.041 |      0.968 | -0.130 |   0.136 |\n| X1_demeaned   |     -1.019 |        0.083 |   -12.345 |      0.000 | -1.181 |  -0.857 |\n---\nRMSE: 2.141 R2: 0.126 \n\n\nWe get the same results as the fixed effect model Y1 ~ X | group_id above. The PyFixest package uses a more efficient algorithm to estimate the fixed effect model, but the intuition is the same.\n\n\n\nYou can update the coefficients of a model object via the update() method, which may be useful in an online learning setting where data arrives sequentially.\nTo see this in action, let us first fit a model on a subset of the data:\n\ndata_subsample = data.sample(frac=0.5)\nm = pf.feols(\"Y ~ X1 + X2\", data=data_subsample)\n# current coefficient vector\nm._beta_hat\n\narray([ 1.09640035, -1.08873836, -0.17390191])\n\n\nThen sample 5 new observations and update the model with the new data. The update rule is\n\\[\n\\hat{\\beta}_{n+1} = \\hat{\\beta}_n + (X_{n+1}' X_{n+1})^{-1} x_{n+1} + (y_{n+1} - x_{n+1} \\hat{\\beta}_n)\n\\]\nfor a new observation \\((x_{n+1}, y_{n+1})\\).\n\nnew_points_id = np.random.choice(list(set(data.index) - set(data_subsample.index)), 5)\nX_new, y_new = (\n    np.c_[np.ones(len(new_points_id)), data.loc[new_points_id][[\"X1\", \"X2\"]].values],\n    data.loc[new_points_id][\"Y\"].values,\n)\nm.update(X_new, y_new)\n\narray([ 1.08984282, -1.08331043, -0.17257353])\n\n\nWe verify that we get the same results if we had estimated the model on the appended data.\n\npf.feols(\n    \"Y ~ X1 + X2\", data=data.loc[data_subsample.index.append(pd.Index(new_points_id))]\n).coef().values\n\narray([ 1.08984282, -1.08331043, -0.17257353])"
  },
  {
    "objectID": "quickstart.html#what-is-a-fixed-effect-model",
    "href": "quickstart.html#what-is-a-fixed-effect-model",
    "title": "Getting Started with PyFixest",
    "section": "",
    "text": "A fixed effect model is a statistical model that includes fixed effects, which are parameters that are estimated to be constant across different groups.\nExample [Panel Data]: In the context of panel data, fixed effects are parameters that are constant across different individuals or time. The typical model example is given by the following equation:\n\\[\nY_{it} = \\beta X_{it} + \\alpha_i + \\psi_t + \\varepsilon_{it}\n\\]\nwhere \\(Y_{it}\\) is the dependent variable for individual \\(i\\) at time \\(t\\), \\(X_{it}\\) is the independent variable, \\(\\beta\\) is the coefficient of the independent variable, \\(\\alpha_i\\) is the individual fixed effect, \\(\\psi_t\\) is the time fixed effect, and \\(\\varepsilon_{it}\\) is the error term. The individual fixed effect \\(\\alpha_i\\) is a parameter that is constant across time for each individual, while the time fixed effect \\(\\psi_t\\) is a parameter that is constant across individuals for each time period.\nNote however that, despite the fact that fixed effects are commonly used in panel setting, one does not need a panel data set to work with fixed effects. For example, cluster randomized trials with cluster fixed effects, or wage regressions with worker and firm fixed effects.\nIn this “quick start” guide, we will show you how to estimate a fixed effect model using the PyFixest package. We do not go into the details of the theory behind fixed effect models, but we focus on how to estimate them using PyFixest."
  },
  {
    "objectID": "quickstart.html#read-sample-data",
    "href": "quickstart.html#read-sample-data",
    "title": "Getting Started with PyFixest",
    "section": "",
    "text": "In a first step, we load the module and some synthetic example data:\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import LetsPlot\nfrom marginaleffects import slopes, avg_slopes\n\nimport pyfixest as pf\n\nLetsPlot.setup_html()\n\nplt.style.use(\"seaborn-v0_8\")\n\n%load_ext watermark\n%config InlineBackend.figure_format = \"retina\"\n%watermark --iversions\n\ndata = pf.get_data()\n\ndata.head()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\npandas    : 2.2.3\nmatplotlib: 3.10.0\npyfixest  : 0.27.0\nnumpy     : 2.0.2\n\n\n\n\n\n\n\n\n\n\nY\nY2\nX1\nX2\nf1\nf2\nf3\ngroup_id\nZ1\nZ2\nweights\n\n\n\n\n0\nNaN\n2.357103\n0.0\n0.457858\n15.0\n0.0\n7.0\n9.0\n-0.330607\n1.054826\n0.661478\n\n\n1\n-1.458643\n5.163147\nNaN\n-4.998406\n6.0\n21.0\n4.0\n8.0\nNaN\n-4.113690\n0.772732\n\n\n2\n0.169132\n0.751140\n2.0\n1.558480\nNaN\n1.0\n7.0\n16.0\n1.207778\n0.465282\n0.990929\n\n\n3\n3.319513\n-2.656368\n1.0\n1.560402\n1.0\n10.0\n11.0\n3.0\n2.869997\n0.467570\n0.021123\n\n\n4\n0.134420\n-1.866416\n2.0\n-3.472232\n19.0\n20.0\n6.0\n14.0\n0.835819\n-3.115669\n0.790815\n\n\n\n\n\n\n\n\ndata.info()\n\n&lt;class 'pandas.core.frame.DataFrame'&gt;\nRangeIndex: 1000 entries, 0 to 999\nData columns (total 11 columns):\n #   Column    Non-Null Count  Dtype  \n---  ------    --------------  -----  \n 0   Y         999 non-null    float64\n 1   Y2        1000 non-null   float64\n 2   X1        999 non-null    float64\n 3   X2        1000 non-null   float64\n 4   f1        999 non-null    float64\n 5   f2        1000 non-null   float64\n 6   f3        1000 non-null   float64\n 7   group_id  1000 non-null   float64\n 8   Z1        999 non-null    float64\n 9   Z2        1000 non-null   float64\n 10  weights   1000 non-null   float64\ndtypes: float64(11)\nmemory usage: 86.1 KB\n\n\nWe see that some of our columns have missing data."
  },
  {
    "objectID": "quickstart.html#ols-estimation",
    "href": "quickstart.html#ols-estimation",
    "title": "Getting Started with PyFixest",
    "section": "",
    "text": "We are interested in the relation between the dependent variable Y and the independent variables X1 using a fixed effect model for group_id. Let’s see how the data looks like:\n\nax = data.plot(kind=\"scatter\", x=\"X1\", y=\"Y\", c=\"group_id\", colormap=\"viridis\")\n\n\n\n\n\n\n\n\nWe can estimate a fixed effects regression via the feols() function. feols() has three arguments: a two-sided model formula, the data, and optionally, the type of inference.\n\nfit = pf.feols(fml=\"Y ~ X1 | group_id\", data=data, vcov=\"HC1\")\ntype(fit)\n\npyfixest.estimation.feols_.Feols\n\n\nThe first part of the formula contains the dependent variable and “regular” covariates, while the second part contains fixed effects.\nfeols() returns an instance of the Fixest class."
  },
  {
    "objectID": "quickstart.html#inspecting-model-results",
    "href": "quickstart.html#inspecting-model-results",
    "title": "Getting Started with PyFixest",
    "section": "",
    "text": "To inspect the results, we can use a summary function or method:\n\nfit.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: group_id\nInference:  HC1\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -1.019 |        0.082 |   -12.352 |      0.000 | -1.181 |  -0.857 |\n---\nRMSE: 2.141 R2: 0.137 R2 Within: 0.126 \n\n\nOr display a formatted regression table:\n\npf.etable(fit)\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n\n\n\n\ncoef\n\n\nX1\n-1.019***\n(0.082)\n\n\nfe\n\n\ngroup_id\nx\n\n\nstats\n\n\nObservations\n998\n\n\nS.E. type\nhetero\n\n\nR2\n0.137\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nAlternatively, the .summarize module contains a summary function, which can be applied on instances of regression model objects or lists of regression model objects. For details on how to customize etable(), please take a look at the dedicated vignette.\n\npf.summary(fit)\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: group_id\nInference:  HC1\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -1.019 |        0.082 |   -12.352 |      0.000 | -1.181 |  -0.857 |\n---\nRMSE: 2.141 R2: 0.137 R2 Within: 0.126 \n\n\nYou can access individual elements of the summary via dedicated methods: .tidy() returns a “tidy” pd.DataFrame, .coef() returns estimated parameters, and se() estimated standard errors. Other methods include pvalue(), confint() and tstat().\n\nfit.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nX1\n-1.019009\n0.082498\n-12.351897\n0.0\n-1.180898\n-0.857119\n\n\n\n\n\n\n\n\nfit.coef()\n\nCoefficient\nX1   -1.019009\nName: Estimate, dtype: float64\n\n\n\nfit.se()\n\nCoefficient\nX1    0.082498\nName: Std. Error, dtype: float64\n\n\n\nfit.tstat()\n\nCoefficient\nX1   -12.351897\nName: t value, dtype: float64\n\n\n\nfit.confint()\n\n\n\n\n\n\n\n\n2.5%\n97.5%\n\n\n\n\nX1\n-1.180898\n-0.857119\n\n\n\n\n\n\n\nLast, model results can be visualized via dedicated methods for plotting:\n\nfit.coefplot()\n# or pf.coefplot([fit])"
  },
  {
    "objectID": "quickstart.html#how-to-interpret-the-results",
    "href": "quickstart.html#how-to-interpret-the-results",
    "title": "Getting Started with PyFixest",
    "section": "",
    "text": "Let’s have a quick d-tour on the intuition behind fixed effects models using the example above. To do so, let us begin by comparing it with a simple OLS model.\n\nfit_simple = pf.feols(\"Y ~ X1\", data=data, vcov=\"HC1\")\n\nfit_simple.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: 0\nInference:  HC1\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept     |      0.919 |        0.112 |     8.223 |      0.000 |  0.699 |   1.138 |\n| X1            |     -1.000 |        0.082 |   -12.134 |      0.000 | -1.162 |  -0.838 |\n---\nRMSE: 2.158 R2: 0.123 \n\n\nWe can compare both models side by side in a regression table:\n\npf.etable([fit, fit_simple])\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n\n\n\n\ncoef\n\n\nX1\n-1.019***\n(0.082)\n-1.000***\n(0.082)\n\n\nIntercept\n\n0.919***\n(0.112)\n\n\nfe\n\n\ngroup_id\nx\n-\n\n\nstats\n\n\nObservations\n998\n998\n\n\nS.E. type\nhetero\nhetero\n\n\nR2\n0.137\n0.123\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nWe see that the X1 coefficient is -1.019, which is less than the value from the OLS model in column (2). Where is the difference coming from? Well, in the fixed effect model we are interested in controlling for the feature group_id. One possibility to do this is by adding a simple dummy variable for each level of group_id.\n\nfit_dummy = pf.feols(\"Y ~ X1 + C(group_id) \", data=data, vcov=\"HC1\")\n\nfit_dummy.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: 0\nInference:  HC1\nObservations:  998\n\n| Coefficient         |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept           |      0.760 |        0.288 |     2.640 |      0.008 |  0.195 |   1.326 |\n| X1                  |     -1.019 |        0.083 |   -12.234 |      0.000 | -1.182 |  -0.856 |\n| C(group_id)[T.1.0]  |      0.380 |        0.451 |     0.844 |      0.399 | -0.504 |   1.264 |\n| C(group_id)[T.2.0]  |      0.084 |        0.389 |     0.216 |      0.829 | -0.680 |   0.848 |\n| C(group_id)[T.3.0]  |      0.790 |        0.415 |     1.904 |      0.057 | -0.024 |   1.604 |\n| C(group_id)[T.4.0]  |     -0.189 |        0.388 |    -0.487 |      0.626 | -0.950 |   0.572 |\n| C(group_id)[T.5.0]  |      0.537 |        0.388 |     1.385 |      0.166 | -0.224 |   1.297 |\n| C(group_id)[T.6.0]  |      0.307 |        0.398 |     0.771 |      0.441 | -0.474 |   1.087 |\n| C(group_id)[T.7.0]  |      0.015 |        0.422 |     0.035 |      0.972 | -0.814 |   0.844 |\n| C(group_id)[T.8.0]  |      0.382 |        0.406 |     0.941 |      0.347 | -0.415 |   1.179 |\n| C(group_id)[T.9.0]  |      0.219 |        0.417 |     0.526 |      0.599 | -0.599 |   1.037 |\n| C(group_id)[T.10.0] |     -0.363 |        0.422 |    -0.861 |      0.390 | -1.191 |   0.465 |\n| C(group_id)[T.11.0] |      0.201 |        0.387 |     0.520 |      0.603 | -0.559 |   0.961 |\n| C(group_id)[T.12.0] |     -0.110 |        0.410 |    -0.268 |      0.788 | -0.915 |   0.694 |\n| C(group_id)[T.13.0] |      0.126 |        0.440 |     0.287 |      0.774 | -0.736 |   0.989 |\n| C(group_id)[T.14.0] |      0.353 |        0.416 |     0.848 |      0.397 | -0.464 |   1.170 |\n| C(group_id)[T.15.0] |      0.469 |        0.398 |     1.179 |      0.239 | -0.312 |   1.249 |\n| C(group_id)[T.16.0] |     -0.135 |        0.396 |    -0.340 |      0.734 | -0.913 |   0.643 |\n| C(group_id)[T.17.0] |     -0.005 |        0.401 |    -0.013 |      0.989 | -0.792 |   0.781 |\n| C(group_id)[T.18.0] |      0.283 |        0.403 |     0.702 |      0.483 | -0.508 |   1.074 |\n---\nRMSE: 2.141 R2: 0.137 \n\n\nThis is does not scale well! Imagine you have 1000 different levels of group_id. You would need to add 1000 dummy variables to your model. This is where fixed effect models come in handy. They allow you to control for these fixed effects without adding all these dummy variables. The way to do it is by a demeaning procedure. The idea is to subtract the average value of each level of group_id from the respective observations. This way, we control for the fixed effects without adding all these dummy variables. Let’s try to do this manually:\n\ndef _demean_column(df: pd.DataFrame, column: str, by: str) -&gt; pd.Series:\n    return df[column] - df.groupby(by)[column].transform(\"mean\")\n\n\nfit_demeaned = pf.feols(\n    fml=\"Y_demeaned ~ X1_demeaned\",\n    data=data.assign(\n        Y_demeaned=lambda df: _demean_column(df, \"Y\", \"group_id\"),\n        X1_demeaned=lambda df: _demean_column(df, \"X1\", \"group_id\"),\n    ),\n    vcov=\"HC1\",\n)\n\nfit_demeaned.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Y_demeaned, Fixed effects: 0\nInference:  HC1\nObservations:  998\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Intercept     |      0.003 |        0.068 |     0.041 |      0.968 | -0.130 |   0.136 |\n| X1_demeaned   |     -1.019 |        0.083 |   -12.345 |      0.000 | -1.181 |  -0.857 |\n---\nRMSE: 2.141 R2: 0.126 \n\n\nWe get the same results as the fixed effect model Y1 ~ X | group_id above. The PyFixest package uses a more efficient algorithm to estimate the fixed effect model, but the intuition is the same."
  },
  {
    "objectID": "quickstart.html#updating-regression-coefficients",
    "href": "quickstart.html#updating-regression-coefficients",
    "title": "Getting Started with PyFixest",
    "section": "",
    "text": "You can update the coefficients of a model object via the update() method, which may be useful in an online learning setting where data arrives sequentially.\nTo see this in action, let us first fit a model on a subset of the data:\n\ndata_subsample = data.sample(frac=0.5)\nm = pf.feols(\"Y ~ X1 + X2\", data=data_subsample)\n# current coefficient vector\nm._beta_hat\n\narray([ 1.09640035, -1.08873836, -0.17390191])\n\n\nThen sample 5 new observations and update the model with the new data. The update rule is\n\\[\n\\hat{\\beta}_{n+1} = \\hat{\\beta}_n + (X_{n+1}' X_{n+1})^{-1} x_{n+1} + (y_{n+1} - x_{n+1} \\hat{\\beta}_n)\n\\]\nfor a new observation \\((x_{n+1}, y_{n+1})\\).\n\nnew_points_id = np.random.choice(list(set(data.index) - set(data_subsample.index)), 5)\nX_new, y_new = (\n    np.c_[np.ones(len(new_points_id)), data.loc[new_points_id][[\"X1\", \"X2\"]].values],\n    data.loc[new_points_id][\"Y\"].values,\n)\nm.update(X_new, y_new)\n\narray([ 1.08984282, -1.08331043, -0.17257353])\n\n\nWe verify that we get the same results if we had estimated the model on the appended data.\n\npf.feols(\n    \"Y ~ X1 + X2\", data=data.loc[data_subsample.index.append(pd.Index(new_points_id))]\n).coef().values\n\narray([ 1.08984282, -1.08331043, -0.17257353])"
  },
  {
    "objectID": "quickstart.html#inference-via-the-wild-bootstrap",
    "href": "quickstart.html#inference-via-the-wild-bootstrap",
    "title": "Getting Started with PyFixest",
    "section": "Inference via the Wild Bootstrap",
    "text": "Inference via the Wild Bootstrap\nIt is also possible to run a wild (cluster) bootstrap after estimation (via the wildboottest module, see MacKinnon, J. G., Nielsen, M. Ø., & Webb, M. D. (2023). Fast and reliable jackknife and bootstrap methods for cluster-robust inference. Journal of Applied Econometrics, 38(5), 671–694.):\n\nfit2 = pf.feols(fml=\"Y ~ X1\", data=data, vcov={\"CRV1\": \"group_id\"})\nfit2.wildboottest(param=\"X1\", reps=999)\n\nparam                             X1\nt value           -8.567586579080423\nPr(&gt;|t|)                         0.0\nbootstrap_type                    11\ninference              CRV(group_id)\nimpose_null                     True\nssc                         1.056615\ndtype: object"
  },
  {
    "objectID": "quickstart.html#the-causal-cluster-variance-estimator",
    "href": "quickstart.html#the-causal-cluster-variance-estimator",
    "title": "Getting Started with PyFixest",
    "section": "The Causal Cluster Variance Estimator",
    "text": "The Causal Cluster Variance Estimator\nAdditionally, PyFixest supports the causal cluster variance estimator following Abadie et al. (2023). Let’s look into it with another data set:\n\ndf = pd.read_stata(\"http://www.damianclarke.net/stata/census2000_5pc.dta\")\n\ndf.head()\n\n\n\n\n\n\n\n\nln_earnings\neduc\nhours\nstate\ncollege\n\n\n\n\n0\n11.91839\n18.0\n50.0\n44.0\n1.0\n\n\n1\n11.48247\n11.0\n42.0\n44.0\n0.0\n\n\n2\n10.46310\n12.0\n42.0\n44.0\n0.0\n\n\n3\n10.22194\n13.0\n40.0\n44.0\n1.0\n\n\n4\n9.21034\n13.0\n8.0\n44.0\n1.0\n\n\n\n\n\n\n\n\naxes = df.plot.hist(column=[\"ln_earnings\"], by=[\"college\"])\n\n\n\n\n\n\n\n\nNow we can estimate the model ln_earnings ~ college where we cluster the standard errors at the state level:\n\nfit3 = pf.feols(\"ln_earnings ~ college\", vcov={\"CRV1\": \"state\"}, data=df)\nfit3.ccv(treatment=\"college\", pk=0.05, n_splits=2, seed=929)\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\n\n\nCCV\n0.4656425903701483\n0.00348\n133.820079\n0.0\n0.458657\n0.472628\n\n\nCRV1\n0.465643\n0.027142\n17.155606\n0.0\n0.411152\n0.520133"
  },
  {
    "objectID": "quickstart.html#randomization-inference",
    "href": "quickstart.html#randomization-inference",
    "title": "Getting Started with PyFixest",
    "section": "Randomization Inference",
    "text": "Randomization Inference\nYou can also conduct inference via randomization inference (see Heß, Stata Journal 2017). PyFixest supports random and cluster random sampling.\n\nfit2.ritest(resampvar=\"X1=0\", reps=1000, cluster=\"group_id\")\n\nH0                                     X1=0\nri-type                     randomization-c\nEstimate                 -1.000085840074156\nPr(&gt;|t|)                                0.0\nStd. Error (Pr(&gt;|t|))                   0.0\n2.5% (Pr(&gt;|t|))                         0.0\n97.5% (Pr(&gt;|t|))                        0.0\nCluster                            group_id\ndtype: object"
  },
  {
    "objectID": "quickstart.html#multiple-testing-corrections-bonferroni-and-romano-wolf",
    "href": "quickstart.html#multiple-testing-corrections-bonferroni-and-romano-wolf",
    "title": "Getting Started with PyFixest",
    "section": "Multiple Testing Corrections: Bonferroni and Romano-Wolf",
    "text": "Multiple Testing Corrections: Bonferroni and Romano-Wolf\nTo correct for multiple testing, p-values can be adjusted via either the Bonferroni, the method by Romano and Wolf (2005), see for example The Romano-Wolf Multiple Hypothesis Correction in Stata, and the method by Westfall & Young (see here).\n\npf.bonferroni([fit, fit2], param=\"X1\").round(3)\n\n\n\n\n\n\n\n\nest0\nest1\n\n\n\n\nEstimate\n-1.019\n-1.000\n\n\nStd. Error\n0.125\n0.117\n\n\nt value\n-8.179\n-8.568\n\n\nPr(&gt;|t|)\n0.000\n0.000\n\n\n2.5%\n-1.281\n-1.245\n\n\n97.5%\n-0.757\n-0.755\n\n\nBonferroni Pr(&gt;|t|)\n0.000\n0.000\n\n\n\n\n\n\n\n\npf.rwolf([fit, fit2], param=\"X1\", reps=9999, seed=1234).round(3)\n\n\n\n\n\n\n\n\nest0\nest1\n\n\n\n\nEstimate\n-1.019\n-1.000\n\n\nStd. Error\n0.125\n0.117\n\n\nt value\n-8.179\n-8.568\n\n\nPr(&gt;|t|)\n0.000\n0.000\n\n\n2.5%\n-1.281\n-1.245\n\n\n97.5%\n-0.757\n-0.755\n\n\nRW Pr(&gt;|t|)\n0.000\n0.000\n\n\n\n\n\n\n\n\npf.wyoung([fit, fit2], param=\"X1\", reps=9999, seed=1234).round(3)\n\n\n\n\n\n\n\n\nest0\nest1\n\n\n\n\nEstimate\n-1.019\n-1.000\n\n\nStd. Error\n0.125\n0.117\n\n\nt value\n-8.179\n-8.568\n\n\nPr(&gt;|t|)\n0.000\n0.000\n\n\n2.5%\n-1.281\n-1.245\n\n\n97.5%\n-0.757\n-0.755\n\n\nWY Pr(&gt;|t|)\n0.000\n0.000"
  },
  {
    "objectID": "quickstart.html#joint-confidence-intervals",
    "href": "quickstart.html#joint-confidence-intervals",
    "title": "Getting Started with PyFixest",
    "section": "Joint Confidence Intervals",
    "text": "Joint Confidence Intervals\nSimultaneous confidence bands for a vector of parameters can be computed via the joint_confint() method. See Simultaneous confidence bands: Theory, implementation, and an application to SVARs for background.\n\nfit_ci = pf.feols(\"Y ~ X1+ C(f1)\", data=data)\nfit_ci.confint(joint=True).head()\n\n\n\n\n\n\n\n\n2.5%\n97.5%\n\n\n\n\nIntercept\n-0.420891\n1.398802\n\n\nX1\n-1.159565\n-0.739317\n\n\nC(f1)[T.1.0]\n1.390843\n3.774456\n\n\nC(f1)[T.2.0]\n-2.831934\n-0.331934\n\n\nC(f1)[T.3.0]\n-1.601185\n0.976518"
  },
  {
    "objectID": "reference/did.estimation.event_study.html",
    "href": "reference/did.estimation.event_study.html",
    "title": "did.estimation.event_study",
    "section": "",
    "text": "did.estimation.event_study(\n    data,\n    yname,\n    idname,\n    tname,\n    gname,\n    xfml=None,\n    estimator='twfe',\n    att=True,\n    cluster='idname',\n)\nEstimate Event Study Model.\nThis function allows for the estimation of treatment effects using different estimators. Currently, it supports “twfe” for the two-way fixed effects estimator and “did2s” for Gardner’s two-step DID2S estimator. Other estimators are in development.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.event_study"
    ]
  },
  {
    "objectID": "reference/did.estimation.event_study.html#parameters",
    "href": "reference/did.estimation.event_study.html#parameters",
    "title": "did.estimation.event_study",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ndata\nDataFrame\nThe DataFrame containing all variables.\nrequired\n\n\nyname\nstr\nThe name of the dependent variable.\nrequired\n\n\nidname\nstr\nThe name of the id variable.\nrequired\n\n\ntname\nstr\nVariable name for calendar period.\nrequired\n\n\ngname\nstr\nUnit-specific time of initial treatment.\nrequired\n\n\nxfml\nstr\nThe formula for the covariates.\nNone\n\n\nestimator\nstr\nThe estimator to use. Options are “did2s” and “twfe”.\n'twfe'\n\n\natt\nbool\nIf True, estimates the average treatment effect on the treated (ATT). If False, estimates the canonical event study design with all leads and lags. Default is True.\nTrue\n\n\ncluster\nOptional[str]\nThe name of the cluster variable.\n'idname'",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.event_study"
    ]
  },
  {
    "objectID": "reference/did.estimation.event_study.html#returns",
    "href": "reference/did.estimation.event_study.html#returns",
    "title": "did.estimation.event_study",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nobject\nA fitted model object of class [Feols(/reference/Feols.qmd).",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.event_study"
    ]
  },
  {
    "objectID": "reference/did.estimation.event_study.html#examples",
    "href": "reference/did.estimation.event_study.html#examples",
    "title": "did.estimation.event_study",
    "section": "Examples",
    "text": "Examples\n\nimport pandas as pd\nimport pyfixest as pf\n\nurl = \"https://raw.githubusercontent.com/py-econometrics/pyfixest/master/pyfixest/did/data/df_het.csv\"\ndf_het = pd.read_csv(url)\n\nfit_twfe = pf.event_study(\n    df_het,\n    yname=\"dep_var\",\n    idname=\"unit\",\n    tname=\"year\",\n    gname=\"g\",\n    estimator=\"twfe\",\n    att=True,\n)\n\nfit_twfe.tidy()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nATT\n1.98254\n0.019093\n103.83491\n0.0\n1.945088\n2.019993",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "did.estimation.event_study"
    ]
  },
  {
    "objectID": "reference/did.visualize.panelview.html",
    "href": "reference/did.visualize.panelview.html",
    "title": "did.visualize.panelview",
    "section": "",
    "text": "did.visualize.panelview(\n    data,\n    unit,\n    time,\n    treat,\n    outcome=None,\n    collapse_to_cohort=False,\n    subsamp=None,\n    units_to_plot=None,\n    sort_by_timing=False,\n    xlab=None,\n    ylab=None,\n    figsize=(11, 3),\n    noticks=False,\n    title=None,\n    legend=False,\n    ax=None,\n    xlim=None,\n    ylim=None,\n)\nGenerate a panel view of the treatment variable over time for each unit.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "did.visualize.panelview"
    ]
  },
  {
    "objectID": "reference/did.visualize.panelview.html#parameters",
    "href": "reference/did.visualize.panelview.html#parameters",
    "title": "did.visualize.panelview",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\ndata\npandas.DataFrame\nThe input dataframe containing the data.\nrequired\n\n\nunit\nstr\nThe column name representing the unit identifier.\nrequired\n\n\ntime\nstr\nThe column name representing the time identifier.\nrequired\n\n\ntreat\nstr\nThe column name representing the treatment variable.\nrequired\n\n\noutcome\nstr\nThe column name representing the outcome variable. If not None, an outcome plot is generated.\nNone\n\n\ncollapse_to_cohort\nbool\nWhether to collapse units into treatment cohorts.\nFalse\n\n\nsubsamp\nint\nThe number of samples to draw from data set for display (default is None).\nNone\n\n\nsort_by_timing\nbool\nWhether to sort the treatment cohorts by the number of treated periods.\nFalse\n\n\nxlab\nstr\nThe label for the x-axis. Default is None, in which case default labels are used.\nNone\n\n\nylab\nstr\nThe label for the y-axis. Default is None, in which case default labels are used.\nNone\n\n\nfigsize\ntuple\nThe figure size for the outcome plot. Default is (11, 3).\n(11, 3)\n\n\nnoticks\nbool\nWhether to display ticks on the plot. Default is False.\nFalse\n\n\ntitle\nstr\nThe title for the plot. Default is None, in which case no title is displayed.\nNone\n\n\nlegend\nbool\nWhether to display a legend. Default is False (since binary treatments are self-explanatory).\nFalse\n\n\nax\nmatplotlib.pyplot.Axes\nThe axes on which to draw the plot. Default is None, in which case a new figure is created.\nNone\n\n\nxlim\ntuple\nThe limits for the x-axis of the plot. Default is None.\nNone\n\n\nylim\ntuple\nThe limits for the y-axis of the plot. Default is None.\nNone\n\n\nunits_to_plot\nlist\nA list of unit to include in the plot. If None, all units in the dataset are plotted.\nNone",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "did.visualize.panelview"
    ]
  },
  {
    "objectID": "reference/did.visualize.panelview.html#returns",
    "href": "reference/did.visualize.panelview.html#returns",
    "title": "did.visualize.panelview",
    "section": "Returns",
    "text": "Returns\n\n\n\nName\nType\nDescription\n\n\n\n\nax\nmatplotlib.pyplot.Axes",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "did.visualize.panelview"
    ]
  },
  {
    "objectID": "reference/did.visualize.panelview.html#examples",
    "href": "reference/did.visualize.panelview.html#examples",
    "title": "did.visualize.panelview",
    "section": "Examples",
    "text": "Examples\n\nimport pandas as pd\nimport numpy as np\nimport pyfixest as pf\n\nurl = \"https://raw.githubusercontent.com/py-econometrics/pyfixest/master/pyfixest/did/data/df_het.csv\"\ndf_het = pd.read_csv(url)\n\n# Inspect treatment assignment\npf.panelview(\n    data = df_het,\n    unit = \"unit\",\n    time = \"year\",\n    treat = \"treat\",\n    subsamp = 50,\n    title = \"Treatment Assignment\"\n)\n\n# Outcome plot\npf.panelview(\n    data = df_het,\n    unit = \"unit\",\n    time = \"year\",\n    outcome = \"dep_var\",\n    treat = \"treat\",\n    subsamp = 50,\n    title = \"Outcome Plot\"\n)",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "did.visualize.panelview"
    ]
  },
  {
    "objectID": "reference/estimation.demean.html",
    "href": "reference/estimation.demean.html",
    "title": "estimation.demean",
    "section": "",
    "text": "estimation.demean(x, flist, weights, tol=1e-08, maxiter=100000)\nDemean an array.\nWorkhorse for demeaning an input array x based on the specified fixed effects and weights via the alternating projections algorithm.",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.demean"
    ]
  },
  {
    "objectID": "reference/estimation.demean.html#parameters",
    "href": "reference/estimation.demean.html#parameters",
    "title": "estimation.demean",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nx\nnumpy.ndarray\nInput array of shape (n_samples, n_features). Needs to be of type float.\nrequired\n\n\nflist\nnumpy.ndarray\nArray of shape (n_samples, n_factors) specifying the fixed effects. Needs to already be converted to integers.\nrequired\n\n\nweights\nnumpy.ndarray\nArray of shape (n_samples,) specifying the weights.\nrequired\n\n\ntol\nfloat\nTolerance criterion for convergence. Defaults to 1e-08.\n1e-08\n\n\nmaxiter\nint\nMaximum number of iterations. Defaults to 100_000.\n100000",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.demean"
    ]
  },
  {
    "objectID": "reference/estimation.demean.html#returns",
    "href": "reference/estimation.demean.html#returns",
    "title": "estimation.demean",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\ntuple[numpy.ndarray, bool]\nA tuple containing the demeaned array of shape (n_samples, n_features) and a boolean indicating whether the algorithm converged successfully.",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.demean"
    ]
  },
  {
    "objectID": "reference/estimation.demean.html#examples",
    "href": "reference/estimation.demean.html#examples",
    "title": "estimation.demean",
    "section": "Examples",
    "text": "Examples\n\nimport numpy as np\nimport pyfixest as pf\nfrom pyfixest.utils.dgps import get_blw\nfrom pyfixest.estimation.demean_ import demean\nfrom formulaic import model_matrix\n\nfml = \"y ~ treat | state + year\"\n\ndata = get_blw()\ndata.head()\n\nY, rhs = model_matrix(fml, data)\nX = rhs[0].drop(columns=\"Intercept\")\nfe = rhs[1].drop(columns=\"Intercept\")\nYX = np.concatenate([Y, X], axis=1)\n\n# to numpy\nY = Y.to_numpy()\nX = X.to_numpy()\nYX = np.concatenate([Y, X], axis=1)\nfe = fe.to_numpy().astype(int)  # demean requires fixed effects as ints!\n\nYX_demeaned, success = demean(YX, fe, weights = np.ones(YX.shape[0]))\nY_demeaned = YX_demeaned[:, 0]\nX_demeaned = YX_demeaned[:, 1:]\n\nprint(np.linalg.lstsq(X_demeaned, Y_demeaned, rcond=None)[0])\nprint(pf.feols(fml, data).coef())\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n[-6.70944555]\nCoefficient\ntreat   -6.709446\nName: Estimate, dtype: float64",
    "crumbs": [
      "Function Reference",
      "Misc / Utilities",
      "estimation.demean"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.feglm.html",
    "href": "reference/estimation.estimation.feglm.html",
    "title": "estimation.estimation.feglm",
    "section": "",
    "text": "estimation.estimation.feglm(\n    fml,\n    data,\n    family,\n    vcov=None,\n    ssc=None,\n    fixef_rm='none',\n    fixef_tol=1e-08,\n    iwls_tol=1e-08,\n    iwls_maxiter=25,\n    collin_tol=1e-10,\n    separation_check=None,\n    solver='np.linalg.solve',\n    drop_intercept=False,\n    i_ref1=None,\n    copy_data=True,\n    store_data=True,\n    lean=False,\n    context=None,\n    split=None,\n    fsplit=None,\n)\nEstimate GLM regression model with fixed effects.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.feglm"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.feglm.html#parameters",
    "href": "reference/estimation.estimation.feglm.html#parameters",
    "title": "estimation.estimation.feglm",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfml\nstr\nA two-sided formula string using fixest formula syntax. Syntax: “Y ~ X1 + X2 | FE1 + FE2”. “|” separates left-hand side and fixed effects. Special syntax includes: - Stepwise regressions (sw, sw0) - Cumulative stepwise regression (csw, csw0) - Multiple dependent variables (Y1 + Y2 ~ X) - Interaction of variables (i(X1,X2)) - Interacted fixed effects (fe1^fe2) Compatible with formula parsing via the formulaic module.\nrequired\n\n\ndata\nDataFrameType\nA pandas or polars dataframe containing the variables in the formula.\nrequired\n\n\nfamily\nstr\nThe family of the GLM model. Options include “gaussian”, “logit” and “probit”.\nrequired\n\n\nvcov\nUnion[VcovTypeOptions, dict[str, str]]\nType of variance-covariance matrix for inference. Options include “iid”, “hetero”, “HC1”, “HC2”, “HC3”, or a dictionary for CRV1/CRV3 inference.\nNone\n\n\nssc\nstr\nA ssc object specifying the small sample correction for inference.\nNone\n\n\nfixef_rm\nFixedRmOptions\nSpecifies whether to drop singleton fixed effects. Options: “none” (default), “singleton”.\n'none'\n\n\nfixef_tol\nfloat\nTolerance for the fixed effects demeaning algorithm. Defaults to 1e-08.\n1e-08\n\n\niwls_tol\nOptional[float]\nTolerance for IWLS convergence, by default 1e-08.\n1e-08\n\n\niwls_maxiter\nOptional[float]\nMaximum number of iterations for IWLS convergence, by default 25.\n25\n\n\ncollin_tol\nfloat\nTolerance for collinearity check, by default 1e-10.\n1e-10\n\n\nseparation_check\nOptional[list[str]]\nMethods to identify and drop separated observations. Either “fe” or “ir”. Executes “fe” by default (when None).\nNone\n\n\nsolver\nSolverOptions, optional.\nThe solver to use for the regression. Can be either “np.linalg.solve” or “np.linalg.lstsq”. Defaults to “np.linalg.solve”.\n'np.linalg.solve'\n\n\ndrop_intercept\nbool\nWhether to drop the intercept from the model, by default False.\nFalse\n\n\ni_ref1\n\nDeprecated with pyfixest version 0.18.0. Please use i-syntax instead, i.e. fepois(‘Y~ i(f1, ref=1)’, data = data) instead of the former fepois(‘Y~ i(f1)’, data = data, i_ref=1).\nNone\n\n\ncopy_data\nbool\nWhether to copy the data before estimation, by default True. If set to False, the data is not copied, which can save memory but may lead to unintended changes in the input data outside of fepois. For example, the input data set is re-index within the function. As far as I know, the only other relevant case is when using interacted fixed effects, in which case you’ll find a column with interacted fixed effects in the data set.\nTrue\n\n\nstore_data\nbool\nWhether to store the data in the model object, by default True. If set to False, the data is not stored in the model object, which can improve performance and save memory. However, it will no longer be possible to access the data via the data attribute of the model object. This has impact on post-estimation capabilities that rely on the data, e.g. predict() or vcov().\nTrue\n\n\nlean\nbool\nFalse by default. If True, then all large objects are removed from the returned result: this will save memory but will block the possibility to use many methods. It is recommended to use the argument vcov to obtain the appropriate standard-errors at estimation time, since obtaining different SEs won’t be possible afterwards.\nFalse\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\nNone\n\n\nsplit\nOptional[str]\nA character string, i.e. ‘split = var’. If provided, the sample is split according to the variable and one estimation is performed for each value of that variable. If you also want to include the estimation for the full sample, use the argument fsplit instead.\nNone\n\n\nfsplit\nOptional[str]\nThis argument is the same as split but also includes the full sample as the first estimation.\nNone",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.feglm"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.feglm.html#returns",
    "href": "reference/estimation.estimation.feglm.html#returns",
    "title": "estimation.estimation.feglm",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nobject\nAn instance of the Fepois class or an instance of class FixestMulti for multiple models specified via fml.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.feglm"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.feglm.html#examples",
    "href": "reference/estimation.estimation.feglm.html#examples",
    "title": "estimation.estimation.feglm",
    "section": "Examples",
    "text": "Examples\nThe fepois() function can be used to estimate a simple Poisson regression model with fixed effects. The following example regresses Y on X1 and X2 with fixed effects for f1 and f2: fixed effects are specified after the | symbol.\n\nimport pyfixest as pf\nimport numpy as np\n\ndata = pf.get_data()\ndata[\"Y\"] = np.where(data[\"Y\"] &gt; 0, 1, 0)\ndata[\"f1\"] = np.where(data[\"f1\"] &gt; data[\"f1\"].median(), \"group1\", \"group2\")\n\nfit_probit = pf.feglm(\"Y ~ X1*f1\", data, family = \"probit\")\nfit_logit = pf.feglm(\"Y ~ X1*f1\", data, family = \"logit\")\nfit_gaussian = pf.feglm(\"Y ~ X1*f1\", data, family = \"gaussian\")\n\npf.etable([fit_probit, fit_logit, fit_gaussian])\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n(3)\n\n\n\n\ncoef\n\n\nX1\n-0.466***\n(0.073)\n-0.752***\n(0.119)\n-0.179***\n(0.027)\n\n\nf1[T.group2]\n-0.118\n(0.133)\n-0.190\n(0.216)\n-0.044\n(0.050)\n\n\nX1:f1[T.group2]\n0.035\n(0.102)\n0.057\n(0.168)\n0.014\n(0.038)\n\n\nIntercept\n0.449***\n(0.096)\n0.724***\n(0.156)\n0.673***\n(0.035)\n\n\nstats\n\n\nObservations\n999\n999\n999\n\n\nS.E. type\niid\niid\niid\n\n\nR2\n-\n-\n-\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\nPyFixest integrates with the marginaleffects package. For example, to compute average marginal effects for the probit model above, you can use the following code:\n\n# we load polars as marginaleffects outputs pl.DataFrame's\nimport polars as pl\nfrom marginaleffects import avg_slopes\npl.concat([avg_slopes(model, variables  = \"X1\") for model in [fit_probit, fit_logit, fit_gaussian]])\n\n\nshape: (3, 9)\n\n\n\nterm\ncontrast\nestimate\nstd_error\nstatistic\np_value\ns_value\nconf_low\nconf_high\n\n\nstr\nstr\nf64\nf64\nf64\nf64\nf64\nf64\nf64\n\n\n\n\n\"X1\"\n\"mean(dY/dX)\"\n-0.448614\n0.051085\n-8.781635\n0.0\ninf\n-0.548739\n-0.348488\n\n\n\"X1\"\n\"mean(dY/dX)\"\n-0.722455\n0.083798\n-8.621427\n0.0\ninf\n-0.886695\n-0.558214\n\n\n\"X1\"\n\"mean(dY/dX)\"\n-0.172566\n0.018802\n-9.177932\n0.0\ninf\n-0.209418\n-0.135715\n\n\n\n\n\n\nWe can also compute marginal effects by group (group average marginal effects):\n\navg_slopes(fit_probit, variables  = \"X1\", by = \"f1\")\n\n\nshape: (2, 10)\n\n\n\nf1\nterm\ncontrast\nestimate\nstd_error\nstatistic\np_value\ns_value\nconf_low\nconf_high\n\n\nstr\nstr\nstr\nf64\nf64\nf64\nf64\nf64\nf64\nf64\n\n\n\n\n\"group1\"\n\"X1\"\n\"mean(dY/dX)\"\n-0.466327\n0.072613\n-6.422116\n1.3439e-10\n32.792824\n-0.608646\n-0.324009\n\n\n\"group2\"\n\"X1\"\n\"mean(dY/dX)\"\n-0.431424\n0.071921\n-5.998564\n1.9907e-9\n28.904075\n-0.572387\n-0.290461\n\n\n\n\n\n\nWe find homogeneous effects by “f1” in the probit model.\nFor more examples of other function arguments, please take a look at the documentation of the feols() function.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.feglm"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.fepois.html",
    "href": "reference/estimation.estimation.fepois.html",
    "title": "estimation.estimation.fepois",
    "section": "",
    "text": "estimation.estimation.fepois(\n    fml,\n    data,\n    vcov=None,\n    ssc=None,\n    fixef_rm='none',\n    fixef_tol=1e-08,\n    iwls_tol=1e-08,\n    iwls_maxiter=25,\n    collin_tol=1e-10,\n    separation_check=None,\n    solver='np.linalg.solve',\n    demeaner_backend='numba',\n    drop_intercept=False,\n    i_ref1=None,\n    copy_data=True,\n    store_data=True,\n    lean=False,\n    context=None,\n    split=None,\n    fsplit=None,\n)\nEstimate Poisson regression model with fixed effects using the ppmlhdfe algorithm.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.fepois"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.fepois.html#parameters",
    "href": "reference/estimation.estimation.fepois.html#parameters",
    "title": "estimation.estimation.fepois",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nfml\nstr\nA two-sided formula string using fixest formula syntax. Syntax: “Y ~ X1 + X2 | FE1 + FE2”. “|” separates left-hand side and fixed effects. Special syntax includes: - Stepwise regressions (sw, sw0) - Cumulative stepwise regression (csw, csw0) - Multiple dependent variables (Y1 + Y2 ~ X) - Interaction of variables (i(X1,X2)) - Interacted fixed effects (fe1^fe2) Compatible with formula parsing via the formulaic module.\nrequired\n\n\ndata\nDataFrameType\nA pandas or polars dataframe containing the variables in the formula.\nrequired\n\n\nvcov\nUnion[VcovTypeOptions, dict[str, str]]\nType of variance-covariance matrix for inference. Options include “iid”, “hetero”, “HC1”, “HC2”, “HC3”, or a dictionary for CRV1/CRV3 inference.\nNone\n\n\nssc\nstr\nA ssc object specifying the small sample correction for inference.\nNone\n\n\nfixef_rm\nFixedRmOptions\nSpecifies whether to drop singleton fixed effects. Options: “none” (default), “singleton”.\n'none'\n\n\nfixef_tol\nfloat\nTolerance for the fixed effects demeaning algorithm. Defaults to 1e-08.\n1e-08\n\n\niwls_tol\nOptional[float]\nTolerance for IWLS convergence, by default 1e-08.\n1e-08\n\n\niwls_maxiter\nOptional[float]\nMaximum number of iterations for IWLS convergence, by default 25.\n25\n\n\ncollin_tol\nfloat\nTolerance for collinearity check, by default 1e-10.\n1e-10\n\n\nseparation_check\nOptional[list[str]]\nMethods to identify and drop separated observations. Either “fe” or “ir”. Executes “fe” by default (when None).\nNone\n\n\nsolver\nSolverOptions, optional.\nThe solver to use for the regression. Can be either “np.linalg.solve” or “np.linalg.lstsq”. Defaults to “np.linalg.solve”.\n'np.linalg.solve'\n\n\ndemeaner_backend\nDemeanerBackendOptions\nThe backend to use for demeaning. Can be either “numba” or “jax”. Defaults to “numba”.\n'numba'\n\n\ndrop_intercept\nbool\nWhether to drop the intercept from the model, by default False.\nFalse\n\n\ni_ref1\n\nDeprecated with pyfixest version 0.18.0. Please use i-syntax instead, i.e. fepois(‘Y~ i(f1, ref=1)’, data = data) instead of the former fepois(‘Y~ i(f1)’, data = data, i_ref=1).\nNone\n\n\ncopy_data\nbool\nWhether to copy the data before estimation, by default True. If set to False, the data is not copied, which can save memory but may lead to unintended changes in the input data outside of fepois. For example, the input data set is re-index within the function. As far as I know, the only other relevant case is when using interacted fixed effects, in which case you’ll find a column with interacted fixed effects in the data set.\nTrue\n\n\nstore_data\nbool\nWhether to store the data in the model object, by default True. If set to False, the data is not stored in the model object, which can improve performance and save memory. However, it will no longer be possible to access the data via the data attribute of the model object. This has impact on post-estimation capabilities that rely on the data, e.g. predict() or vcov().\nTrue\n\n\nlean\nbool\nFalse by default. If True, then all large objects are removed from the returned result: this will save memory but will block the possibility to use many methods. It is recommended to use the argument vcov to obtain the appropriate standard-errors at estimation time, since obtaining different SEs won’t be possible afterwards.\nFalse\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\nNone\n\n\nsplit\nOptional[str]\nA character string, i.e. ‘split = var’. If provided, the sample is split according to the variable and one estimation is performed for each value of that variable. If you also want to include the estimation for the full sample, use the argument fsplit instead.\nNone\n\n\nfsplit\nOptional[str]\nThis argument is the same as split but also includes the full sample as the first estimation.\nNone",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.fepois"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.fepois.html#returns",
    "href": "reference/estimation.estimation.fepois.html#returns",
    "title": "estimation.estimation.fepois",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nobject\nAn instance of the Fepois class or an instance of class FixestMulti for multiple models specified via fml.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.fepois"
    ]
  },
  {
    "objectID": "reference/estimation.estimation.fepois.html#examples",
    "href": "reference/estimation.estimation.fepois.html#examples",
    "title": "estimation.estimation.fepois",
    "section": "Examples",
    "text": "Examples\nThe fepois() function can be used to estimate a simple Poisson regression model with fixed effects. The following example regresses Y on X1 and X2 with fixed effects for f1 and f2: fixed effects are specified after the | symbol.\n\nimport pyfixest as pf\n\ndata = pf.get_data(model = \"Fepois\")\nfit = pf.fepois(\"Y ~ X1 + X2 | f1 + f2\", data)\nfit.summary()\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n###\n\nEstimation:  Poisson\nDep. var.: Y, Fixed effects: f1+f2\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.007 |        0.035 |    -0.190 |      0.850 | -0.075 |   0.062 |\n| X2            |     -0.015 |        0.010 |    -1.449 |      0.147 | -0.035 |   0.005 |\n---\nDeviance: 1068.169 \n\n\nFor more examples on the use of other function arguments, please take a look at the documentation of the feols() function.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.estimation.fepois"
    ]
  },
  {
    "objectID": "reference/estimation.feglm_.Feglm.html",
    "href": "reference/estimation.feglm_.Feglm.html",
    "title": "estimation.feglm_.Feglm",
    "section": "",
    "text": "estimation.feglm_.Feglm(\n    self,\n    FixestFormula,\n    data,\n    ssc_dict,\n    drop_singletons,\n    drop_intercept,\n    weights,\n    weights_type,\n    collin_tol,\n    fixef_tol,\n    lookup_demeaned_data,\n    tol,\n    maxiter,\n    solver,\n    store_data=True,\n    copy_data=True,\n    lean=False,\n    sample_split_var=None,\n    sample_split_value=None,\n    separation_check=None,\n    context=0,\n)\nAbstract base class for the estimation of a fixed-effects GLM model.\n\n\n\n\n\nName\nDescription\n\n\n\n\nget_fit\nFit the GLM model via iterated weighted least squares.\n\n\npredict\nReturn predicted values from regression model.\n\n\nprepare_model_matrix\nPrepare model inputs for estimation.\n\n\nresidualize\nResidualize v and X by flist using weights.\n\n\nto_array\nTurn estimation DataFrames to np arrays.\n\n\n\n\n\nestimation.feglm_.Feglm.get_fit()\nFit the GLM model via iterated weighted least squares.\nAll equations in the code refer to Stammann ‘Fast and Feasible Estimation of Generalized Linear Models with High-Dimensional k-way fixed effects’: https://arxiv.org/pdf/1707.01815\n\n\n\nestimation.feglm_.Feglm.predict(\n    newdata=None,\n    atol=1e-06,\n    btol=1e-06,\n    type='link',\n)\nReturn predicted values from regression model.\nReturn a flat np.array with predicted values of the regression model. If new fixed effect levels are introduced in newdata, predicted values for such observations will be set to NaN.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nnewdata\nUnion[None, pd.DataFrame]\nA pd.DataFrame with the new data, to be used for prediction. If None (default), uses the data used for fitting the model.\nNone\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\ntype\nstr\nThe type of prediction to be computed. Can be either “response” (default) or “link”. If type=“response”, the output is at the level of the response variable, i.e., it is the expected predictor E(Y|X). If “link”, the output is at the level of the explanatory variables, i.e., the linear predictor X @ beta.\n'link'\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nA flat array with the predicted values of the regression model.\n\n\n\n\n\n\n\nestimation.feglm_.Feglm.prepare_model_matrix()\nPrepare model inputs for estimation.\n\n\n\nestimation.feglm_.Feglm.residualize(v, X, flist, weights, tol)\nResidualize v and X by flist using weights.\n\n\n\nestimation.feglm_.Feglm.to_array()\nTurn estimation DataFrames to np arrays.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feglm_.Feglm"
    ]
  },
  {
    "objectID": "reference/estimation.feglm_.Feglm.html#methods",
    "href": "reference/estimation.feglm_.Feglm.html#methods",
    "title": "estimation.feglm_.Feglm",
    "section": "",
    "text": "Name\nDescription\n\n\n\n\nget_fit\nFit the GLM model via iterated weighted least squares.\n\n\npredict\nReturn predicted values from regression model.\n\n\nprepare_model_matrix\nPrepare model inputs for estimation.\n\n\nresidualize\nResidualize v and X by flist using weights.\n\n\nto_array\nTurn estimation DataFrames to np arrays.\n\n\n\n\n\nestimation.feglm_.Feglm.get_fit()\nFit the GLM model via iterated weighted least squares.\nAll equations in the code refer to Stammann ‘Fast and Feasible Estimation of Generalized Linear Models with High-Dimensional k-way fixed effects’: https://arxiv.org/pdf/1707.01815\n\n\n\nestimation.feglm_.Feglm.predict(\n    newdata=None,\n    atol=1e-06,\n    btol=1e-06,\n    type='link',\n)\nReturn predicted values from regression model.\nReturn a flat np.array with predicted values of the regression model. If new fixed effect levels are introduced in newdata, predicted values for such observations will be set to NaN.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nnewdata\nUnion[None, pd.DataFrame]\nA pd.DataFrame with the new data, to be used for prediction. If None (default), uses the data used for fitting the model.\nNone\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/ scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\ntype\nstr\nThe type of prediction to be computed. Can be either “response” (default) or “link”. If type=“response”, the output is at the level of the response variable, i.e., it is the expected predictor E(Y|X). If “link”, the output is at the level of the explanatory variables, i.e., the linear predictor X @ beta.\n'link'\n\n\natol\nFloat\nStopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\nbtol\nFloat\nAnother stopping tolerance for scipy.sparse.linalg.lsqr(). See https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.lsqr.html\n1e-6\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nA flat array with the predicted values of the regression model.\n\n\n\n\n\n\n\nestimation.feglm_.Feglm.prepare_model_matrix()\nPrepare model inputs for estimation.\n\n\n\nestimation.feglm_.Feglm.residualize(v, X, flist, weights, tol)\nResidualize v and X by flist using weights.\n\n\n\nestimation.feglm_.Feglm.to_array()\nTurn estimation DataFrames to np arrays.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feglm_.Feglm"
    ]
  },
  {
    "objectID": "reference/estimation.felogit_.Felogit.html",
    "href": "reference/estimation.felogit_.Felogit.html",
    "title": "estimation.felogit_.Felogit",
    "section": "",
    "text": "estimation.felogit_.Felogit\nestimation.felogit_.Felogit(\n    self,\n    FixestFormula,\n    data,\n    ssc_dict,\n    drop_singletons,\n    drop_intercept,\n    weights,\n    weights_type,\n    collin_tol,\n    fixef_tol,\n    lookup_demeaned_data,\n    tol,\n    maxiter,\n    solver,\n    store_data=True,\n    copy_data=True,\n    lean=False,\n    sample_split_var=None,\n    sample_split_value=None,\n    separation_check=None,\n    context=0,\n)\nClass for the estimation of a fixed-effects logit model.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.felogit_.Felogit"
    ]
  },
  {
    "objectID": "reference/estimation.feols_compressed_.FeolsCompressed.html",
    "href": "reference/estimation.feols_compressed_.FeolsCompressed.html",
    "title": "estimation.feols_compressed_.FeolsCompressed",
    "section": "",
    "text": "estimation.feols_compressed_.FeolsCompressed(\n    self,\n    FixestFormula,\n    data,\n    ssc_dict,\n    drop_singletons,\n    drop_intercept,\n    weights,\n    weights_type,\n    collin_tol,\n    fixef_tol,\n    lookup_demeaned_data,\n    solver,\n    demeaner_backend='numba',\n    store_data=True,\n    copy_data=True,\n    lean=False,\n    context=0,\n    reps=100,\n    seed=None,\n    sample_split_var=None,\n    sample_split_value=None,\n)\nNon-user-facing class for compressed regression with fixed effects.\nSee the paper “You only compress once” by Wong et al (https://arxiv.org/abs/2102.11297) for details on regression compression.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nFixestFormula\nFixestFormula\nThe formula object.\nrequired\n\n\ndata\npd.DataFrame\nThe data.\nrequired\n\n\nssc_dict\ndict[str, Union[str, bool]]\nThe ssc dictionary.\nrequired\n\n\ndrop_singletons\nbool\nWhether to drop columns with singleton fixed effects.\nrequired\n\n\ndrop_intercept\nbool\nWhether to include an intercept.\nrequired\n\n\nweights\nOptional[str]\nThe column name of the weights. None if no weights are used. For this method, weights needs to be None.\nrequired\n\n\nweights_type\nOptional[str]\nThe type of weights. For this method, weights_type needs to be ‘fweights’.\nrequired\n\n\ncollin_tol\nfloat\nThe tolerance level for collinearity.\nrequired\n\n\nfixef_tol\nfloat\nThe tolerance level for the fixed effects.\nrequired\n\n\nlookup_demeaned_data\ndict[str, pd.DataFrame]\nThe lookup table for demeaned data.\nrequired\n\n\nsolver\nstr\nThe solver to use.\nrequired\n\n\nstore_data\nbool\nWhether to store the data.\nTrue\n\n\ncopy_data\nbool\nWhether to copy the data.\nTrue\n\n\nlean\nbool\nWhether to keep memory-heavy objects as attributes or not.\nFalse\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\n0\n\n\nreps\nint\nThe number of bootstrap repetitions. Default is 100. Only used for CRV1 inference, where a wild cluster bootstrap is used.\n100\n\n\nseed\nOptional[int]\nThe seed for the random number generator. Only relevant for CRV1 inference, where a wild cluster bootstrap is used.\nNone\n\n\n\n\n\n\n\n\n\nName\nDescription\n\n\n\n\npredict\nCompute predicted values.\n\n\nprepare_model_matrix\nPrepare model inputs for estimation.\n\n\nvcov\nCompute the variance-covariance matrix for the compressed regression.\n\n\n\n\n\nestimation.feols_compressed_.FeolsCompressed.predict(\n    newdata=None,\n    atol=1e-06,\n    btol=1e-06,\n    type='link',\n)\nCompute predicted values.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nnewdata\nOptional[DataFrameType]\nThe new data. If None, makes a prediction based on the uncompressed data set.\nNone\n\n\natol\nfloat\nThe absolute tolerance.\n1e-06\n\n\nbtol\nfloat\nThe relative tolerance.\n1e-06\n\n\ntype\nstr\nThe type of prediction.\n'link'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nThe predicted values. If newdata is None, the predicted values are based on the uncompressed data set.\n\n\n\n\n\n\n\nestimation.feols_compressed_.FeolsCompressed.prepare_model_matrix()\nPrepare model inputs for estimation.\n\n\n\nestimation.feols_compressed_.FeolsCompressed.vcov(vcov, data=None)\nCompute the variance-covariance matrix for the compressed regression.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feols_compressed_.FeolsCompressed"
    ]
  },
  {
    "objectID": "reference/estimation.feols_compressed_.FeolsCompressed.html#parameters",
    "href": "reference/estimation.feols_compressed_.FeolsCompressed.html#parameters",
    "title": "estimation.feols_compressed_.FeolsCompressed",
    "section": "",
    "text": "Name\nType\nDescription\nDefault\n\n\n\n\nFixestFormula\nFixestFormula\nThe formula object.\nrequired\n\n\ndata\npd.DataFrame\nThe data.\nrequired\n\n\nssc_dict\ndict[str, Union[str, bool]]\nThe ssc dictionary.\nrequired\n\n\ndrop_singletons\nbool\nWhether to drop columns with singleton fixed effects.\nrequired\n\n\ndrop_intercept\nbool\nWhether to include an intercept.\nrequired\n\n\nweights\nOptional[str]\nThe column name of the weights. None if no weights are used. For this method, weights needs to be None.\nrequired\n\n\nweights_type\nOptional[str]\nThe type of weights. For this method, weights_type needs to be ‘fweights’.\nrequired\n\n\ncollin_tol\nfloat\nThe tolerance level for collinearity.\nrequired\n\n\nfixef_tol\nfloat\nThe tolerance level for the fixed effects.\nrequired\n\n\nlookup_demeaned_data\ndict[str, pd.DataFrame]\nThe lookup table for demeaned data.\nrequired\n\n\nsolver\nstr\nThe solver to use.\nrequired\n\n\nstore_data\nbool\nWhether to store the data.\nTrue\n\n\ncopy_data\nbool\nWhether to copy the data.\nTrue\n\n\nlean\nbool\nWhether to keep memory-heavy objects as attributes or not.\nFalse\n\n\ncontext\nint or Mapping[str, Any]\nA dictionary containing additional context variables to be used by formulaic during the creation of the model matrix. This can include custom factorization functions, transformations, or any other variables that need to be available in the formula environment.\n0\n\n\nreps\nint\nThe number of bootstrap repetitions. Default is 100. Only used for CRV1 inference, where a wild cluster bootstrap is used.\n100\n\n\nseed\nOptional[int]\nThe seed for the random number generator. Only relevant for CRV1 inference, where a wild cluster bootstrap is used.\nNone",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feols_compressed_.FeolsCompressed"
    ]
  },
  {
    "objectID": "reference/estimation.feols_compressed_.FeolsCompressed.html#methods",
    "href": "reference/estimation.feols_compressed_.FeolsCompressed.html#methods",
    "title": "estimation.feols_compressed_.FeolsCompressed",
    "section": "",
    "text": "Name\nDescription\n\n\n\n\npredict\nCompute predicted values.\n\n\nprepare_model_matrix\nPrepare model inputs for estimation.\n\n\nvcov\nCompute the variance-covariance matrix for the compressed regression.\n\n\n\n\n\nestimation.feols_compressed_.FeolsCompressed.predict(\n    newdata=None,\n    atol=1e-06,\n    btol=1e-06,\n    type='link',\n)\nCompute predicted values.\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nnewdata\nOptional[DataFrameType]\nThe new data. If None, makes a prediction based on the uncompressed data set.\nNone\n\n\natol\nfloat\nThe absolute tolerance.\n1e-06\n\n\nbtol\nfloat\nThe relative tolerance.\n1e-06\n\n\ntype\nstr\nThe type of prediction.\n'link'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\nnp.ndarray\nThe predicted values. If newdata is None, the predicted values are based on the uncompressed data set.\n\n\n\n\n\n\n\nestimation.feols_compressed_.FeolsCompressed.prepare_model_matrix()\nPrepare model inputs for estimation.\n\n\n\nestimation.feols_compressed_.FeolsCompressed.vcov(vcov, data=None)\nCompute the variance-covariance matrix for the compressed regression.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feols_compressed_.FeolsCompressed"
    ]
  },
  {
    "objectID": "reference/estimation.feprobit_.Feprobit.html",
    "href": "reference/estimation.feprobit_.Feprobit.html",
    "title": "estimation.feprobit_.Feprobit",
    "section": "",
    "text": "estimation.feprobit_.Feprobit\nestimation.feprobit_.Feprobit(\n    self,\n    FixestFormula,\n    data,\n    ssc_dict,\n    drop_singletons,\n    drop_intercept,\n    weights,\n    weights_type,\n    collin_tol,\n    fixef_tol,\n    lookup_demeaned_data,\n    tol,\n    maxiter,\n    solver,\n    store_data=True,\n    copy_data=True,\n    lean=False,\n    sample_split_var=None,\n    sample_split_value=None,\n    separation_check=None,\n    context=0,\n)\nClass for the estimation of a fixed-effects probit model.",
    "crumbs": [
      "Function Reference",
      "Estimation Classes",
      "estimation.feprobit_.Feprobit"
    ]
  },
  {
    "objectID": "reference/estimation.rwolf.html",
    "href": "reference/estimation.rwolf.html",
    "title": "estimation.rwolf",
    "section": "",
    "text": "estimation.rwolf(models, param, reps, seed, sampling_method='wild-bootstrap')\nCompute Romano-Wolf adjusted p-values for multiple hypothesis testing.\nFor each model, it is assumed that tests to adjust are of the form “param = 0”. This function uses the wildboottest() method for running the bootstrap, hence models of type Feiv or Fepois are not supported.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.rwolf"
    ]
  },
  {
    "objectID": "reference/estimation.rwolf.html#parameters",
    "href": "reference/estimation.rwolf.html#parameters",
    "title": "estimation.rwolf",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodels\nlist[Feols] or FixestMulti\nA list of models for which the p-values should be computed, or a FixestMulti object. Models of type Feiv or Fepois are not supported.\nrequired\n\n\nparam\nstr\nThe parameter for which the p-values should be computed.\nrequired\n\n\nreps\nint\nThe number of bootstrap replications.\nrequired\n\n\nseed\nint\nThe seed for the random number generator.\nrequired\n\n\nsampling_method\nstr\nSampling method for computing resampled statistics. Users can choose either bootstrap(‘wild-bootstrap’) or randomization inference(‘ri’)\n'wild-bootstrap'",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.rwolf"
    ]
  },
  {
    "objectID": "reference/estimation.rwolf.html#returns",
    "href": "reference/estimation.rwolf.html#returns",
    "title": "estimation.rwolf",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npd.DataFrame\nA DataFrame containing estimation statistics, including the Romano-Wolf adjusted p-values.",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.rwolf"
    ]
  },
  {
    "objectID": "reference/estimation.rwolf.html#examples",
    "href": "reference/estimation.rwolf.html#examples",
    "title": "estimation.rwolf",
    "section": "Examples",
    "text": "Examples\n\nimport pyfixest as pf\nfrom pyfixest.utils import get_data\n\ndata = get_data().dropna()\nfit = pf.feols(\"Y ~ Y2 + X1 + X2\", data=data)\npf.rwolf(fit, \"X1\", reps=9999, seed=123)\n\nfit1 = pf.feols(\"Y ~ X1\", data=data)\nfit2 = pf.feols(\"Y ~ X1 + X2\", data=data)\nrwolf_df = pf.rwolf([fit1, fit2], \"X1\", reps=9999, seed=123)\n\n# use randomization inference - dontrun as too slow\n# rwolf_df = pf.rwolf([fit1, fit2], \"X1\", reps=9999, seed=123, sampling_method = \"ri\")\n\nrwolf_df\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\nest0\nest1\n\n\n\n\nEstimate\n-1.001930\n-0.995197\n\n\nStd. Error\n0.084823\n0.082194\n\n\nt value\n-11.811964\n-12.107957\n\n\nPr(&gt;|t|)\n0.000000\n0.000000\n\n\n2.5%\n-1.168383\n-1.156490\n\n\n97.5%\n-0.835476\n-0.833904\n\n\nRW Pr(&gt;|t|)\n0.000100\n0.000100",
    "crumbs": [
      "Function Reference",
      "Estimation Functions",
      "estimation.rwolf"
    ]
  },
  {
    "objectID": "reference/report.coefplot.html",
    "href": "reference/report.coefplot.html",
    "title": "report.coefplot",
    "section": "",
    "text": "report.coefplot(\n    models,\n    alpha=0.05,\n    figsize=None,\n    yintercept=0,\n    xintercept=None,\n    rotate_xticks=0,\n    title=None,\n    coord_flip=True,\n    keep=None,\n    drop=None,\n    exact_match=False,\n    plot_backend='lets_plot',\n    labels=None,\n    joint=None,\n    seed=None,\n    ax=None,\n)\nPlot model coefficients with confidence intervals.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.coefplot"
    ]
  },
  {
    "objectID": "reference/report.coefplot.html#parameters",
    "href": "reference/report.coefplot.html#parameters",
    "title": "report.coefplot",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodels\nA supported model object (Feols, Fepois, Feiv, FixestMulti) or a list of\nFeols, Fepois & Feiv models.\nrequired\n\n\nfigsize\ntuple or None\nThe size of the figure. If None, the default size is used.\nNone\n\n\nalpha\nfloat\nThe significance level for the confidence intervals.\n0.05\n\n\nyintercept\nfloat or None\nThe value at which to draw a horizontal line on the plot. Default is 0.\n0\n\n\nxintercept\nfloat or None\nThe value at which to draw a vertical line on the plot. Default is None.\nNone\n\n\nrotate_xticks\nfloat\nThe angle in degrees to rotate the xticks labels. Default is 0 (no rotation).\n0\n\n\ntitle\nstr\nThe title of the plot.\nNone\n\n\ncoord_flip\nbool\nWhether to flip the coordinates of the plot. Default is True.\nTrue\n\n\nkeep\nOptional[Union[list, str]]\nThe pattern for retaining coefficient names. You can pass a string (one pattern) or a list (multiple patterns). Default is keeping all coefficients. You should use regular expressions to select coefficients. “age”, # would keep all coefficients containing age r”^tr”, # would keep all coefficients starting with tr r”\\d$“, # would keep all coefficients ending with number Output will be in the order of the patterns.\nNone\n\n\ndrop\nOptional[Union[list, str]]\nThe pattern for excluding coefficient names. You can pass a string (one pattern) or a list (multiple patterns). Syntax is the same as for keep. Default is keeping all coefficients. Parameter keep and drop can be used simultaneously.\nNone\n\n\nexact_match\nbool\nWhether to use exact match for keep and drop. Default is False. If True, the pattern will be matched exactly to the coefficient name instead of using regular expressions.\nFalse\n\n\nplot_backend\nstr\nThe plotting backend to use between “lets_plot” (default) and “matplotlib”.\n'lets_plot'\n\n\nlabels\nOptional[dict]\nA dictionary to relabel the variables. The keys are the original variable names and the values the new names. The renaming is applied after the selection of the coefficients via keep and drop.\nNone\n\n\njoint\nOptional[Union[str, bool]]\nWhether to plot simultaneous confidence bands for the coefficients. If True, simultaneous confidence bands are plotted. If False, “standard” confidence intervals are plotted. If “both”, both are plotted in one figure. Default is None, which returns the standard confidence intervals. Note that this option is not available for objects of type FixestMulti, i.e. multiple estimation.\nNone\n\n\nseed\nOptional[int]\nThe seed for the random number generator. Default is None. Only required / used when joint is True.\nNone",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.coefplot"
    ]
  },
  {
    "objectID": "reference/report.coefplot.html#returns",
    "href": "reference/report.coefplot.html#returns",
    "title": "report.coefplot",
    "section": "Returns",
    "text": "Returns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nobject\nA lets-plot figure.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.coefplot"
    ]
  },
  {
    "objectID": "reference/report.coefplot.html#examples",
    "href": "reference/report.coefplot.html#examples",
    "title": "report.coefplot",
    "section": "Examples",
    "text": "Examples\n\nimport pyfixest as pf\nfrom pyfixest.report.utils import rename_categoricals\n\ndf = pf.get_data()\nfit1 = pf.feols(\"Y ~ X1\", data = df)\nfit2 = pf.feols(\"Y ~ X1 + X2\", data = df)\nfit3 = pf.feols(\"Y ~ X1 + X2 | f1\", data = df)\nfit4 = pf.feols(\"Y ~ C(X1)\", data = df)\n\npf.coefplot([fit1, fit2, fit3])\npf.coefplot([fit4], labels = rename_categoricals(fit1._coefnames))\n\npf.coefplot([fit1], joint = \"both\")",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.coefplot"
    ]
  },
  {
    "objectID": "reference/report.etable.html",
    "href": "reference/report.etable.html",
    "title": "report.etable",
    "section": "",
    "text": "report.etable(\n    models,\n    type='gt',\n    signif_code=None,\n    coef_fmt='b \\n (se)',\n    custom_stats=None,\n    keep=None,\n    drop=None,\n    exact_match=False,\n    labels=None,\n    show_fe=True,\n    show_se_type=True,\n    felabels=None,\n    notes='',\n    model_heads=None,\n    head_order='dh',\n    custom_model_stats=None,\n    filename=None,\n    print_tex=False,\n    **kwargs,\n)\nCreate an esttab-like table from a list of models.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.etable"
    ]
  },
  {
    "objectID": "reference/report.etable.html#parameters",
    "href": "reference/report.etable.html#parameters",
    "title": "report.etable",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodels\nA supported model object (Feols, Fepois, Feiv, FixestMulti) or a list of\nFeols, Fepois & Feiv models.\nrequired\n\n\ntype\nstr\nType of output. Either “df” for pandas DataFrame, “md” for markdown, “gt” for great_tables, or “tex” for LaTeX table. Default is “gt”.\n'gt'\n\n\nsignif_code\nlist\nSignificance levels for the stars. Default is None, which sets [0.001, 0.01, 0.05]. If None, no stars are printed.\nNone\n\n\ncoef_fmt\nstr\nThe format of the coefficient (b), standard error (se), t-stats (t), and p-value (p). Default is \"b \\n (se)\". Spaces , parentheses (), brackets [], newlines \\n are supported.\n'b \\n (se)'\n\n\ncustom_stats\nOptional[dict]\nA dictionary of custom statistics. “b”, “se”, “t”, or “p” are reserved.\nNone\n\n\nkeep\nOptional[Union[list, str]]\nThe pattern for retaining coefficient names. You can pass a string (one pattern) or a list (multiple patterns). Default is keeping all coefficients. You should use regular expressions to select coefficients. “age”, # would keep all coefficients containing age r”^tr”, # would keep all coefficients starting with tr r”\\d$“, # would keep all coefficients ending with number Output will be in the order of the patterns.\nNone\n\n\ndrop\nOptional[Union[list, str]]\nThe pattern for excluding coefficient names. You can pass a string (one pattern) or a list (multiple patterns). Syntax is the same as for keep. Default is keeping all coefficients. Parameter keep and drop can be used simultaneously.\nNone\n\n\nexact_match\nOptional[bool]\nWhether to use exact match for keep and drop. Default is False. If True, the pattern will be matched exactly to the coefficient name instead of using regular expressions.\nFalse\n\n\nlabels\nOptional[dict]\nA dictionary to relabel the variables. The keys are the original variable names and the values the new names. Note that interaction terms will also be relabeled using the labels of the individual variables. The command is applied after the keep and drop commands.\nNone\n\n\nshow_fe\nOptional[bool]\nWhether to show the rows with fixed effects markers. Default is True.\nTrue\n\n\nshow_se_type\nOptional[bool]\nWhether to show the rows with standard error type. Default is True.\nTrue\n\n\nfelabels\nOptional[dict]\nA dictionary to relabel the fixed effects. Only needed if you want to relabel the FE lines with a different label than the one specied for the respective variable in the labels dictionary. The command is applied after the keep and drop commands.\nNone\n\n\ndigits\n\nThe number of digits to round to.\nrequired\n\n\nthousands_sep\n\nThe thousands separator. Default is False.\nrequired\n\n\nscientific_notation\n\nWhether to use scientific notation. Default is True.\nrequired\n\n\nscientific_notation_threshold\n\nThe threshold for using scientific notation. Default is 10_000.\nrequired\n\n\nnotes\nstr\nCustom table notes. Default shows the significance levels and the format of the coefficient cell.\n''\n\n\nmodel_heads\nOptional[list]\nAdd custom headlines to models when output as df or latex. Length of list must correspond to number of models. Default is None.\nNone\n\n\nhead_order\nOptional[str]\nString to determine the display of the table header when output as df or latex. Allowed values are “dh”, “hd”, “d”, “h”, or ““. When head_order is”dh”, the dependent variable is displayed first, followed by the custom model_heads (provided the user has specified them). With “hd” it is the other way around. When head_order is “d”, only the dependent variable and model numbers are displayed and with “” only the model numbers. Default is “dh”.\n'dh'\n\n\nfilename\nOptional[str]\nThe filename to save the LaTeX table to. If None, the LaTeX code is returned as a string. Default is None.\nNone\n\n\nprint_tex\nOptional[bool]\nWhether to print the LaTeX code to the console. Default is False.\nFalse",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.etable"
    ]
  },
  {
    "objectID": "reference/report.etable.html#returns",
    "href": "reference/report.etable.html#returns",
    "title": "report.etable",
    "section": "Returns",
    "text": "Returns\n\n\n\n\n\n\n\n\nName\nType\nDescription\n\n\n\n\n\npandas.DataFrame\nA styled DataFrame with the coefficients and standard errors of the models. When output is “tex”, the LaTeX code is returned as a string.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.etable"
    ]
  },
  {
    "objectID": "reference/report.etable.html#examples",
    "href": "reference/report.etable.html#examples",
    "title": "report.etable",
    "section": "Examples",
    "text": "Examples\nFor more examples, take a look at the regression tables and summary statistics vignette.\n\nimport pyfixest as pf\n\n# load data\ndf = pf.get_data()\nfit1 = pf.feols(\"Y~X1 + X2 | f1\", df)\nfit2 = pf.feols(\"Y~X1 + X2 | f1 + f2\", df)\n\npf.etable([fit1, fit2])\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n\n\n\n\n\n\n\n\n\n\n\n\nY\n\n\n(1)\n(2)\n\n\n\n\ncoef\n\n\nX1\n-0.950***\n(0.067)\n-0.924***\n(0.061)\n\n\nX2\n-0.174***\n(0.018)\n-0.174***\n(0.015)\n\n\nfe\n\n\nf1\nx\nx\n\n\nf2\n-\nx\n\n\nstats\n\n\nObservations\n997\n997\n\n\nS.E. type\nby: f1\nby: f1\n\n\nR2\n0.489\n0.659\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.etable"
    ]
  },
  {
    "objectID": "reference/report.summary.html",
    "href": "reference/report.summary.html",
    "title": "report.summary",
    "section": "",
    "text": "report.summary(models, digits=3)\nPrint a summary of estimation results for each estimated model.\nFor each model, this method prints a header indicating the fixed-effects and the dependent variable, followed by a table of coefficient estimates with standard errors, t-values, and p-values.",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.summary"
    ]
  },
  {
    "objectID": "reference/report.summary.html#parameters",
    "href": "reference/report.summary.html#parameters",
    "title": "report.summary",
    "section": "Parameters",
    "text": "Parameters\n\n\n\n\n\n\n\n\n\nName\nType\nDescription\nDefault\n\n\n\n\nmodels\nA supported model object (Feols, Fepois, Feiv, FixestMulti) or a list of\nFeols, Fepois & Feiv models.\nrequired\n\n\ndigits\nint\nThe number of decimal places to round the summary statistics to. Default is 3.\n3",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.summary"
    ]
  },
  {
    "objectID": "reference/report.summary.html#returns",
    "href": "reference/report.summary.html#returns",
    "title": "report.summary",
    "section": "Returns",
    "text": "Returns\n\n\n\nName\nType\nDescription\n\n\n\n\n\nNone",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.summary"
    ]
  },
  {
    "objectID": "reference/report.summary.html#examples",
    "href": "reference/report.summary.html#examples",
    "title": "report.summary",
    "section": "Examples",
    "text": "Examples\n\nimport pyfixest as pf\n\n# load data\ndf = pf.get_data()\nfit1 = pf.feols(\"Y~X1 + X2 | f1\", df)\nfit2 = pf.feols(\"Y~X1 + X2 | f1 + f2\", df)\nfit3 = pf.feols(\"Y~X1 + X2 | f1 + f2 + f3\", df)\n\npf.summary([fit1, fit2, fit3])\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: f1\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.950 |        0.067 |   -14.273 |      0.000 | -1.086 |  -0.813 |\n| X2            |     -0.174 |        0.018 |    -9.469 |      0.000 | -0.212 |  -0.137 |\n---\nRMSE: 1.648 R2: 0.489 R2 Within: 0.239 \n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: f1+f2\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.924 |        0.061 |   -15.165 |      0.000 | -1.049 |  -0.799 |\n| X2            |     -0.174 |        0.015 |   -11.918 |      0.000 | -0.204 |  -0.144 |\n---\nRMSE: 1.346 R2: 0.659 R2 Within: 0.303 \n###\n\nEstimation:  OLS\nDep. var.: Y, Fixed effects: f1+f2+f3\nInference:  CRV1\nObservations:  997\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| X1            |     -0.957 |        0.039 |   -24.645 |      0.000 | -1.037 |  -0.878 |\n| X2            |     -0.194 |        0.009 |   -21.730 |      0.000 | -0.212 |  -0.176 |\n---\nRMSE: 0.97 R2: 0.823 R2 Within: 0.481",
    "crumbs": [
      "Function Reference",
      "Summarize and Visualize",
      "report.summary"
    ]
  },
  {
    "objectID": "replicating-the-effect.html",
    "href": "replicating-the-effect.html",
    "title": "Replicating Examples from “The Effect”",
    "section": "",
    "text": "This notebook replicates code examples from Nick Huntington-Klein’s book on causal inference, The Effect.\nfrom causaldata import Mroz, gapminder, organ_donations, restaurant_inspections\n\nimport pyfixest as pf\n\n%load_ext watermark\n%watermark --iversions\n\n\n            \n            \n            \n\n\n\n            \n            \n            \n\n\npyfixest  : 0.27.0\ncausaldata: 0.1.5"
  },
  {
    "objectID": "replicating-the-effect.html#chapter-4-describing-relationships",
    "href": "replicating-the-effect.html#chapter-4-describing-relationships",
    "title": "Replicating Examples from “The Effect”",
    "section": "Chapter 4: Describing Relationships",
    "text": "Chapter 4: Describing Relationships\n\n# Read in data\ndt = Mroz.load_pandas().data\n# Keep just working women\ndt = dt.query(\"lfp\")\n# Create unlogged earnings\ndt.loc[:, \"earn\"] = dt[\"lwg\"].apply(\"exp\")\n\n# 5. Run multiple linear regression models by succesively adding controls\nfit = pf.feols(fml=\"lwg ~ csw(inc, wc, k5)\", data=dt, vcov=\"iid\")\npf.etable(fit)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlwg\n\n\n(1)\n(2)\n(3)\n\n\n\n\ncoef\n\n\ninc\n0.010**\n(0.003)\n0.005\n(0.003)\n0.005\n(0.003)\n\n\nwc\n\n0.342***\n(0.075)\n0.349***\n(0.075)\n\n\nk5\n\n\n-0.072\n(0.087)\n\n\nIntercept\n1.007***\n(0.071)\n0.972***\n(0.070)\n0.982***\n(0.071)\n\n\nstats\n\n\nObservations\n428\n428\n428\n\n\nS.E. type\niid\niid\niid\n\n\nR2\n0.020\n0.066\n0.068\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)"
  },
  {
    "objectID": "replicating-the-effect.html#chapter-13-regression",
    "href": "replicating-the-effect.html#chapter-13-regression",
    "title": "Replicating Examples from “The Effect”",
    "section": "Chapter 13: Regression",
    "text": "Chapter 13: Regression\n\nExample 1\n\nres = restaurant_inspections.load_pandas().data\nres.inspection_score = res.inspection_score.astype(float)\nres.NumberofLocations = res.NumberofLocations.astype(float)\nres.dtypes\n\nfit = pf.feols(fml=\"inspection_score ~ NumberofLocations\", data=res)\npf.etable([fit])\n\n\n\n\n\n\n\n\n\n\n\n\ninspection_score\n\n\n(1)\n\n\n\n\ncoef\n\n\nNumberofLocations\n-0.019***\n(0.000)\n\n\nIntercept\n94.866***\n(0.046)\n\n\nstats\n\n\nObservations\n27178\n\n\nS.E. type\niid\n\n\nR2\n0.065\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\n\n\nExample 2\n\ndf = restaurant_inspections.load_pandas().data\n\nfit1 = pf.feols(\n    fml=\"inspection_score ~ NumberofLocations + I(NumberofLocations^2) + Year\", data=df\n)\nfit2 = pf.feols(fml=\"inspection_score ~ NumberofLocations*Weekend + Year\", data=df)\n\npf.etable([fit1, fit2])\n\n\n\n\n\n\n\n\n\n\n\n\n\ninspection_score\n\n\n(1)\n(2)\n\n\n\n\ncoef\n\n\nNumberofLocations\n-0.075***\n(0.019)\n-0.019***\n(0.000)\n\n\nI(NumberofLocations ^ 2)\n0.056**\n(0.019)\n\n\n\nYear\n-0.065***\n(0.006)\n-0.065***\n(0.006)\n\n\nWeekend\n\n1.759***\n(0.488)\n\n\nNumberofLocations:Weekend\n\n-0.010\n(0.008)\n\n\nIntercept\n225.504***\n(12.409)\n225.126***\n(12.415)\n\n\nstats\n\n\nObservations\n27178\n27178\n\n\nS.E. type\niid\niid\n\n\nR2\n0.069\n0.069\n\n\n\nSignificance levels: * p &lt; 0.05, ** p &lt; 0.01, *** p &lt; 0.001. Format of coefficient cell: Coefficient (Std. Error)\n\n\n\n\n\n\n\n        \n\n\n\n\nExample 3: HC Standard Errors\n\npf.feols(fml=\"inspection_score ~ Year + Weekend\", data=df, vcov=\"HC3\").summary()\n\n###\n\nEstimation:  OLS\nDep. var.: inspection_score, Fixed effects: 0\nInference:  HC3\nObservations:  27178\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |    2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|--------:|--------:|\n| Intercept     |    185.380 |       12.150 |    15.257 |      0.000 | 161.564 | 209.196 |\n| Year          |     -0.046 |        0.006 |    -7.551 |      0.000 |  -0.057 |  -0.034 |\n| Weekend       |      2.057 |        0.353 |     5.829 |      0.000 |   1.365 |   2.749 |\n---\nRMSE: 6.248 R2: 0.003 \n\n\n\n\nExample 4: Clustered Standard Errors\n\npf.feols(\n    fml=\"inspection_score ~ Year + Weekend\", data=df, vcov={\"CRV1\": \"Weekend\"}\n).tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nIntercept\n185.380033\n3.264345\n56.789343\n0.011209\n143.902592\n226.857474\n\n\nYear\n-0.045640\n0.001624\n-28.107556\n0.022640\n-0.066272\n-0.025008\n\n\nWeekend\n2.057166\n0.001401\n1468.256799\n0.000434\n2.039364\n2.074969\n\n\n\n\n\n\n\n\n\nExample 5: Bootstrap Inference\n\nfit = pf.feols(fml=\"inspection_score ~ Year + Weekend\", data=df)\nfit.wildboottest(reps=999, param=\"Year\")\n\nparam                 Year\nt value           -7.55233\nPr(&gt;|t|)               0.0\nbootstrap_type          11\ninference               HC\nimpose_null           True\nssc               1.000074\ndtype: object"
  },
  {
    "objectID": "replicating-the-effect.html#chapter-16-fixed-effects",
    "href": "replicating-the-effect.html#chapter-16-fixed-effects",
    "title": "Replicating Examples from “The Effect”",
    "section": "Chapter 16: Fixed Effects",
    "text": "Chapter 16: Fixed Effects\n\nExample 1\ntba\n\n\nExample 2\n\ngm = gapminder.load_pandas().data\ngm[\"logGDPpercap\"] = gm[\"gdpPercap\"].apply(\"log\")\n\nfit = pf.feols(fml=\"lifeExp ~ C(country) + np.log(gdpPercap)\", data=gm)\nfit.tidy().head()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nIntercept\n-27.773459\n2.500533\n-11.107015\n0.000000e+00\n-32.678217\n-22.868701\n\n\nC(country)[T.Albania]\n17.782625\n2.195160\n8.100835\n1.110223e-15\n13.476853\n22.088397\n\n\nC(country)[T.Algeria]\n5.241055\n2.214496\n2.366704\n1.806875e-02\n0.897356\n9.584755\n\n\nC(country)[T.Angola]\n-13.907122\n2.201727\n-6.316460\n3.481857e-10\n-18.225777\n-9.588468\n\n\nC(country)[T.Argentina]\n8.132158\n2.272781\n3.578065\n3.567229e-04\n3.674133\n12.590183\n\n\n\n\n\n\n\n\n\nExample 3: TWFE\n\n# Set our individual and time (index) for our data\nfit = pf.feols(fml=\"lifeExp ~ np.log(gdpPercap) | country + year\", data=gm)\nfit.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: lifeExp, Fixed effects: country+year\nInference:  CRV1\nObservations:  1704\n\n| Coefficient       |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:------------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| np.log(gdpPercap) |      1.450 |        0.677 |     2.141 |      0.034 |  0.111 |   2.788 |\n---\nRMSE: 3.267 R2: 0.936 R2 Within: 0.019"
  },
  {
    "objectID": "replicating-the-effect.html#chapter-18-difference-in-differences",
    "href": "replicating-the-effect.html#chapter-18-difference-in-differences",
    "title": "Replicating Examples from “The Effect”",
    "section": "Chapter 18: Difference-in-Differences",
    "text": "Chapter 18: Difference-in-Differences\n\nExample 1\n\nod = organ_donations.load_pandas().data\n\n# Create Treatment Variable\nod[\"California\"] = od[\"State\"] == \"California\"\nod[\"After\"] = od[\"Quarter_Num\"] &gt; 3\nod[\"Treated\"] = 1 * (od[\"California\"] & od[\"After\"])\n\ndid = pf.feols(fml=\"Rate ~ Treated | State + Quarter\", data=od)\ndid.summary()\n\n###\n\nEstimation:  OLS\nDep. var.: Rate, Fixed effects: State+Quarter\nInference:  CRV1\nObservations:  162\n\n| Coefficient   |   Estimate |   Std. Error |   t value |   Pr(&gt;|t|) |   2.5% |   97.5% |\n|:--------------|-----------:|-------------:|----------:|-----------:|-------:|--------:|\n| Treated       |     -0.022 |        0.006 |    -3.733 |      0.001 | -0.035 |  -0.010 |\n---\nRMSE: 0.022 R2: 0.979 R2 Within: 0.009 \n\n\n\n\nExample 3: Dynamic Treatment Effect\n\nod = organ_donations.load_pandas().data\n\n# Create Treatment Variable\nod[\"California\"] = od[\"State\"] == \"California\"\n# od[\"Quarter_Num\"] = pd.Categorical(od.Quarter_Num)\nod[\"California\"] = od.California.astype(float)\n\ndid2 = pf.feols(\n    fml=\"Rate ~ i(Quarter_Num, California,ref=3) | State + Quarter_Num\", data=od\n)\n\ndid2.tidy()\n\n\n\n\n\n\n\n\nEstimate\nStd. Error\nt value\nPr(&gt;|t|)\n2.5%\n97.5%\n\n\nCoefficient\n\n\n\n\n\n\n\n\n\n\nC(Quarter_Num, contr.treatment(base=3))[T.1]:California\n-0.002942\n0.004986\n-0.590105\n0.560215\n-0.013191\n0.007307\n\n\nC(Quarter_Num, contr.treatment(base=3))[T.2]:California\n0.006296\n0.002222\n2.833502\n0.008782\n0.001729\n0.010864\n\n\nC(Quarter_Num, contr.treatment(base=3))[T.4]:California\n-0.021565\n0.004937\n-4.368464\n0.000178\n-0.031713\n-0.011418\n\n\nC(Quarter_Num, contr.treatment(base=3))[T.5]:California\n-0.020292\n0.004387\n-4.625529\n0.000090\n-0.029310\n-0.011275\n\n\nC(Quarter_Num, contr.treatment(base=3))[T.6]:California\n-0.022165\n0.009820\n-2.257160\n0.032627\n-0.042351\n-0.001980"
  }
]