Running statlingo with local, offline Large Language Models (LLMs) is an excellent way to avoid internet dependencies, external API costs, and API key requirements. This is particularly useful in classroom settings, private enterprise environments, or when working with sensitive data.
WarningImportant Notice: Local Model Capabilities & Hallucinations
While local/offline LLMs are highly convenient, smaller parameter models (such as 1B to 3B parameters like llama3.2:1b) are prone to severe statistical hallucinations. They frequently:
Confuse predictor and response variables.
Invert the direction of effects (e.g., interpreting positive coefficients as negative).
Misdefine statistics (e.g. confusing F-statistics with t-statistics) or misinterpret Adjusted \(R^2\) behaviors.
For reliable statistical explanations, we highly recommend using at least an 8B+ parameter model (such as gemma4) locally, or using production cloud APIs (such as Gemini 3.5 Flash/Pro, Claude Sonnet 5, etc.).
This guide shows how to run statlingo offline using locally hosted models via Ollama or Llama.cpp.
1. Using Ollama (Recommended)
Ollama is a lightweight, easy-to-use framework for running LLMs locally on macOS, Linux, and Windows.
Open your terminal and pull a small, lightweight model of your choice:
# Llama 3.2 (1-billion parameters) - Recommended for speed and basic capabilityollama pull llama3.2:1b# Gemma 4 (8-billion parameters) - Recommended for high-quality offline explanationsollama pull gemma4
Create a custom model with expanded context (highly recommended): By default, Ollama enforces a default context size of 2048 tokens. When using OpenAI-compatible libraries like Python’s chatlas, the model output can easily be truncated before it is finished. To avoid this, you can define a custom model utilizing an Ollama Modelfile to increase both the context size (num_ctx) and maximum generation limit (num_predict).
Create a file named Modelfile with the following content:
FROM gemma4PARAMETER num_ctx 8192PARAMETER num_predict 8192
Then build the new model in your terminal:
ollama create gemma4-long -f Modelfile
Now you can use "gemma4-long" in your code, and Ollama will automatically allocate a larger context window on the server side!
Step B: Run with the R Package
The R package integrates with Ollama via ellmer::chat_ollama().
library(statlingo)library(ellmer)# 1. Fit your statistical modelmodel <-lm(dist ~ speed, data = cars)# 2. Initialize the local Ollama client (default port is 11434)client <-chat_ollama(model ="gemma4-long")# 3. Generate the natural language explanationexplanation <-explain(model, client = client, audience ="student")print(explanation)
## Interpretation of the Linear Regression Model (`dist ~ speed`)
This analysis uses a linear regression model based on R's `lm()` function. The goal of this model is to determine if there is a statistically significant *linear relationship* between a continuous predictor variable, **speed**, and a continuous response variable, **distance** ($\text{dist}$).
The underlying equation we are estimating is:
$$\text{Distance} = \beta_0 + \beta_1 (\text{Speed}) + \epsilon$$
### 1. Overview of Model Fit
Before diving into the coefficients, it's helpful to summarize what the model tells us about its overall predictive strength and reliability.
* **Multiple R-squared:** $0.6511$
* This value represents the proportion of the total variation in `dist` that is accounted for by the predictor variable, `speed`. In practical terms, approximately **65.11%** of the variability observed in distance can be explained by changes in speed based on this model. This indicates a moderately strong fit.
* **Adjusted R-squared:** $0.6438$
* This is a modified version of $R^2$. It adjusts the score downward when adding predictors that do not substantially improve the model (i.e., if we add extra variables, it helps prevent us from overestimating the model's true explanatory power). Since both values are very close, it suggests that `speed` is contributing meaningfully to the prediction of distance.
* **F-statistic and p-value:** $F(1, 48) = 89.57$, $p\text{-value}: 1.49 \times 10^{-12}$
* This test assesses the overall null hypothesis: that *all* coefficients (excluding the intercept) are simultaneously zero, meaning no predictor variable contributes to explaining distance.
* The extremely small p-value ($p < 0.001$) is highly significant. We strongly reject the null hypothesis; therefore, we conclude that **the model as a whole is statistically significant**, and at least one of our predictors (`speed`) contributes significantly to predicting distance.
### 2. Analysis of Residuals
Residuals are the differences between the observed values ($\text{dist}$) and the values predicted by the line (the fitted values). They represent the unexplained variation or the model's error ($\epsilon$).
* **Summary:** $\text{Min}=-29.069, 1Q=-9.525, \text{Median}=-2.272, 3Q=9.215, \text{Max}=43.201$
* The distribution appears somewhat wide, with a large range from $-29$ to $+43$.
* A median residual close to zero ($\approx -2.27$) is ideal for the model, as it suggests that the errors are symmetrically distributed around the regression line.
### 3. Interpretation of Coefficients
This table details the quantitative relationship between `speed` and `dist`. We interpret these coefficients *holding all other variables constant* (in this case, since we only have one predictor, this means interpreting the standalone relationship).
| Term | Estimate | Std. Error | t value | Pr(>|t|) (p-value) | Interpretation |
| :--- | :---: | :---: | :---: | :---: | :--- |
| **Intercept** | $-17.5791$ | $6.7584$ | $-2.601$ | $0.0123 *$ | The predicted distance when speed is 0 (theoretically at $x=0$). |
| **speed** | $3.9324$ | $0.4155$ | $9.464$ | $< 0.001 ***$ | For every one-unit increase in speed, the distance is expected to increase by **3.93 units**. |
#### A. The Predictor Variable: `speed`
* **Estimate ($3.9324$):** This is the most critical finding. It means that, according to the model, increasing the speed by 1 unit (e.g., 1 mile per hour) is associated with an average increase of $3.93$ units in distance, assuming linear conditions apply.
* **p-value ($\ll 0.001$):** The highly minuscule p-value indicates *strong statistical evidence* that `speed` is not zero; it is a significant predictor of distance. We are extremely confident that this relationship exists in the population from which the data was drawn.
#### B. The Intercept ($(Intercept)$)
* **Estimate ($-17.5791$):** This represents the baseline predicted distance when speed is zero.
* ***Caution:*** You must always consider if $x=0$ is a realistic or meaningful physical value in your study context. If running the model at theoretical speeds like 0 results in values outside the observed data range, relying on the intercept can be misleading.
* **p-value ($0.0123 *$):** This value is significant based on the $0.05$ threshold defined by one star $(*)$.
***Significance Codes Explanation:*** The stars indicate how statistically unusual a p-value must be to reject the null hypothesis (that true coefficient = 0). Three stars (`***`) mean that we are extremely confident that the relationship is real and not due to random chance.
### 4. Model Assumptions and Diagnostics for Future Checks
While the model provides strong results, any linear regression depends on certain assumptions. As you continue your studies, it is crucial to check these assumptions:
1. **Linearity:** (The relationship must be straight).
* **Check Used:** Plotting **Residuals vs. Fitted Values**.
* **What to look for:** The points should appear as a *random scatter cloud* centered around the horizontal line at $y=0$. If you see obvious curves (e.g., an inverted U-shape or an exponential curve), the linear assumption is violated, and you might need to transform the variable (e.g., use $\text{log}(\text{speed})$).
2. **Homoscedasticity:** (The variance of the errors must be constant across all predicted values).
* **Check Used:** Examine the **Residuals vs. Fitted Values** plot again.
* **What to look for:** The spread of points should be uniform and consistent, like a horizontal band. If you see a pattern (e.g., a cone shape or a funnel shape—where variance increases as prediction magnitude increases), this violates the assumption (a condition called *heteroscedasticity*).
3. **Normality:** (The errors must follow a normal distribution).
* **Check Used:** **Normal Q-Q Plot of Residuals**.
* **What to look for:** The points should closely follow a straight, diagonal line. Deviations suggest the residuals are not normally distributed.
***Pro Tip:*** Always use graphical methods (plotting) because they provide more intuition than formal statistical tests when checking model assumptions!
***
*Caution: This explanation was generated by a Large Language Model. Users should critically review the output and consult additional statistical resources or experts to ensure correctness and a full understanding.*
Step C: Run with the Python Package
The Python package integrates with Ollama via chatlas.ChatOllama.
import statsmodels.api as smfrom chatlas import ChatOllamafrom statlingo import explain# 1. Fit your statistical modelduncan_data = sm.datasets.get_rdataset("Duncan", "carData").datay = duncan_data["prestige"]X = sm.add_constant(duncan_data[["income"]])model = sm.OLS(y, X).fit()# 2. Initialize the local Ollama client (default port is 11434)client = ChatOllama(model="gemma4-long", kwargs={"timeout": 600.0})# 3. Generate the natural language explanationexplanation = explain(model_object=model, client=client, audience="student")print(explanation["text"])
## Interpretation of Linear Regression Model Results
This output presents the results of an Ordinary Least Squares (OLS) regression model designed to explore the linear relationship between **prestige** (the dependent variable, or predicted outcome) and **income** (the predictor variable).
Here is a thorough interpretation of each section, explaining what these figures mean in the context of your research question.
### Model Overview and Goodness-of-Fit
This section tells us, at a glance, how well the model—using income to predict prestige—performed overall.
* **Model Equation:** The analysis suggests an equation in the form:
$$\text{prestige} = \beta_0 + \beta_1 (\text{income}) + \epsilon$$
Where $\beta_0$ is the intercept, $\beta_1$ is the coefficient for income, and $\epsilon$ is the error term.
* **R-squared ($\mathbf{R^2}$): 0.702**
This is perhaps the most common statistic! $R^2$ represents the proportion of the variance in the dependent variable (**prestige**) that is predictable from the independent variable (**income**). An $R^2$ of 0.702 means that approximately **70.2%** of the variation observed in prestige can be accounted for by changes in income, according to this model. This suggests a reasonably strong fit.
* **Adjusted R-squared: 0.695**
The Adjusted $R^2$ is a modified version of $R^2$. It accounts for the number of predictors included in the model. Because it slightly penalizes adding unnecessary variables, it is generally preferred over the standard $R^2$, especially when comparing different models. The slight drop from 0.702 to 0.695 suggests that while including income improves the fit very little compared to what might be expected, it still provides useful predictive power.
* **F-statistic: 101.3 and Prob (F-statistic): $7.14 \times 10^{-13}$**
This tests the *overall significance* of the entire set of predictors in the model.
* The F-statistic value itself tells you how large the variation explained by the model is compared to the unexplained variation (error). A larger value generally indicates a better fit.
* The associated **$p$-value ($7.14 \times 10^{-13}$)** is extremely small, much less than the standard significance threshold of 0.05. Because this $p$-value is so tiny, we **strongly reject the null hypothesis** that *all* coefficients (except perhaps the intercept) are zero. In plain terms: **Overall, your model is statistically significant; income is a useful predictor of prestige.**
### Coefficient Interpretation (The Heart of the Model)
This table tells you the specific relationship ($\beta$ values) for each variable. Always interpret these estimates in the context of your variables' units.
| Term | Estimate (coef) | Std. Error (std err) | t-value (t) | P>\|t\| ($p$-value) | Interpretation |
| :--- | :--- | :--- | :--- | :--- | :--- |
| **Intercept (const)** | 2.4566 | 5.190 | 0.473 | 0.638 | Not statistically significant. This is the expected prestige if income was zero. Since the $p$-value is high, we cannot confidently say this intercept value is accurate or meaningful for your data range. |
| **Income** | 1.0804 | 0.107 | 10.062 | $\mathbf{0.000}$ | **Highly significant.** This is the key finding: For every one-unit increase in a person’s `income`, their predicted `prestige` increases by **1.0804 units**. The highly small $p$-value ($0.000$) tells us that this observed relationship is extremely unlikely to have occurred merely by random chance. |
**Key Takeaways from the Coefficients:**
* ***P>|t| (The $p$-value):*** This is the probability of observing a result as extreme as yours, assuming the null hypothesis (that the true value for that coefficient is zero) were correct. Since the $p$-value for `income` is $0.000$, we are highly confident that income *does* have a positive relationship with prestige.
* ***The Confidence Interval \[0.864, 1.297]:*** This interval (the two columns flanking $t$) provides the range where we are 95% certain to find the true population coefficient estimate. Since this entire interval is above zero, it reinforces the conclusion that `income` has a positive effect on `prestige`.
### Model Assumptions and Diagnostics Checks
The bottom block of diagnostics reports information about the underlying conditions of your model. While some issues are noted here, they suggest you should proceed with **graphical checking** (see below).
* **Durbin-Watson: 1.627**
This statistic is used to check if there is *autocorrelation* in residuals. For cross-section data, it's not strictly required, but for time series data, a value close to **2.0** is ideal, indicating that errors are independent over time. The reading of 1.627 suggests some deviation from perfect independence, suggesting caution or careful consideration if this data was collected sequentially.
* **Jarque-Bera (JB) and Prob(JB):**
These test for the *normality* of the residuals. The $p$-value ($0.000253$) is very small, indicating a statistically significant departure from perfect normal distribution. This suggests that your errors may not be perfectly normally distributed—a common finding in real-world data.
* **Cond. No. (Condition Number): 96.7**
This measures the degree of multicollinearity (how correlated your *predictors* are with each other). Lower numbers (typically below 100) suggest a lower risk of severe collinearity. Because you only used one predictor (`income`), this number is not deeply informative here, but it indicates that there shouldn't be major issues among your predictors.
### Summary and Recommendations for Model Deepening
In summary, the model is statistically significant: **We have strong evidence that as income increases, prestige tends to increase.**
However, several diagnostic warnings suggest that while the *relationship* is clear, the model's theoretical foundations might be slightly challenged by the data properties.
Since I cannot view your residual plots, I strongly recommend performing these graphical checks to confirm appropriate model usage:
1. **Residuals vs. Fitted Values Plot:** This plot should show a random scattering of points centered around zero, with no discernible pattern (like a curve or a funnel shape).
* *What it helps check:* Linearity and Homoscedasticity (constant variance). If you see a clear U-shape or inverted U-shape, the relationship might be curved, meaning a linear model is inappropriate.
2. **Q-Q Plot of Residuals:** This plot compares your residuals to what they would look like if they were perfectly normal.
* *What it helps check:* Normality. If the points fall roughly along a straight line, the normality assumption holds well.
3. **Residuals vs. Predicted Plot (or Scale-Location):** This simply re-checks for constant variance and identifies potential outliers (points far away from the main cluster).
***
*Caution: This explanation was generated by a Large Language Model. Users should critically review the output and consult additional statistical resources or experts to ensure correctness and a full understanding.*
2. Using Llama.cpp (via OpenAI-Compatible Server)
Llama.cpp allows highly optimized local LLM inference. You can use it with statlingo by running its built-in HTTP server (llama-server), which exposes an API compatible with OpenAI’s endpoint.
Step A: Start the Llama.cpp Server
Run the local server on your machine, specifying your downloaded GGUF model file and a port (e.g. 8080):