Home › Research Methodology › Regression Analysis Explained
Below, we explain regression in plain language and then build a real model, notebook-style: what predicts how often a research paper is cited? Every result is calculated live from the ScholarsColab dataset, and you can run the same code yourself.
Regression essentials at a glance
| Term | Plain meaning |
|---|---|
| Dependent variable (Y) | The outcome you want to explain |
| Independent variables (X) | The factors you think influence it |
| Coefficient | How much Y changes when that X increases by one unit, others held constant |
| Intercept | The predicted Y when all X values are zero |
| p-value of a coefficient | Whether that factor’s effect is distinguishable from zero |
| R² | Share of the variation in Y the model explains (0 to 1) |
Worked example: what predicts a paper’s citations?
The data: 41,792 papers, mostly published between 1998 and 2026, by 967 ScholarsColab mentors (data updated 15 October 2026). No titles, journal names or researcher identities are included in the dataset you will load.
Step 1: Load the data
import numpy as np
import pandas as pd
from datetime import date
# The ScholarsColab Research Methods Index (papers level): anonymised, updated daily
DATA = "https://scholarscolab.in/wp-json/scholarscolab/v1/research-methods-data?level=papers"
papers = pd.read_csv(DATA, comment="#") # lines starting with # hold the citation
def p_text(p):
return "< 0.001" if p < 0.001 else f"= {p:.3f}"
print(papers.shape)
papers.head()(41792, 15)
| year | citations | venue_type | venue_group | title_words | title_colon | review | systematic | machine_learning | deep_learning | iot | blockchain | covid | sustainability | discipline | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2023.0 | 31 | journal | Other journals | 12 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Medicine & health |
| 1 | 2024.0 | 24 | journal | Other journals | 13 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | Medicine & health |
| 2 | 2024.0 | 12 | journal | Other journals | 16 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Medicine & health |
| 3 | 2024.0 | 9 | journal | Other journals | 20 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Medicine & health |
| 4 | 2024.0 | 9 | journal | Generic "International Journal of" | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Medicine & health |
Step 2: Prepare the variables
Our outcome is the number of citations. Because citations are extremely skewed (most papers have a few, some have thousands), we model their logarithm. Our first predictor is the paper’s age.
THIS_YEAR = date.today().year
df = papers.dropna(subset=["year"]).copy()
df = df[df["year"] >= THIS_YEAR - 30]
df["age"] = THIS_YEAR - df["year"] # years since publication
df["log_citations"] = np.log(df["citations"] + 1) # reduces the effect of a few huge values
df[["age", "citations", "log_citations"]].describe().round(2)| age | citations | log_citations | |
|---|---|---|---|
| count | 39348.00 | 39348.00 | 39348.00 |
| mean | 6.54 | 25.82 | 1.73 |
| std | 5.55 | 236.46 | 1.54 |
| min | 0.00 | 0.00 | 0.00 |
| 25% | 2.00 | 0.00 | 0.00 |
| 50% | 5.00 | 4.00 | 1.61 |
| 75% | 9.00 | 16.00 | 2.83 |
| max | 30.00 | 19177.00 | 9.86 |
Notice how far the mean of citations sits above the median (the 50% row), and how much smaller the spread becomes on the log scale.
Step 3: Simple regression, and its graph
Start with one predictor: does a paper collect more citations as it gets older?
import statsmodels.formula.api as smf
import matplotlib.pyplot as plt
simple = smf.ols("log_citations ~ age", data=df).fit()
print(f"log_citations = {simple.params['Intercept']:.3f} + {simple.params['age']:.3f} × age"
f" (R² = {simple.rsquared:.3f})")
sample = df.sample(2000, random_state=1) # plot a sample so the points stay readable
fig, ax = plt.subplots(figsize=(8, 4.5))
ax.scatter(sample["age"], sample["log_citations"], s=8, alpha=0.25)
x = np.linspace(0, 30, 50)
ax.plot(x, simple.params["Intercept"] + simple.params["age"] * x, color="green", linewidth=3)
ax.set_xlabel("Age of paper (years)")
ax.set_ylabel("log(1 + citations)")
plt.show()log_citations = 1.235 + 0.076 × age (R² = 0.075)
Step 4: Multiple regression
Now we add more factors at once: whether the paper is a review, the length of its title, whether the title has a colon, the type of venue, and the research discipline. Each coefficient now shows that factor’s effect with all the others held constant.
model = smf.ols(
'log_citations ~ age + review + title_words + title_colon'
' + C(venue_group, Treatment("Other journals")) + C(discipline)',
data=df).fit()
def tidy(name): # shorter names for the table
name = name.replace('C(venue_group, Treatment("Other journals"))[T.', "venue: ")
return name.replace("C(discipline)[T.", "discipline: ").rstrip("]")
table = pd.DataFrame({"coef": model.params, "p-value": model.pvalues})
table["% change in citations"] = (np.exp(table["coef"]) - 1) * 100
table.index = [tidy(i) for i in table.index]
print(f"R² = {model.rsquared:.3f}, n = {int(model.nobs):,}")
table.drop(index="Intercept").round(3)R² = 0.179, n = 39,348
| coef | p-value | % change in citations | |
|---|---|---|---|
| venue: Conference | -0.390 | 0.000 | -32.272 |
| venue: Generic "International Journal of" | -0.308 | 0.000 | -26.521 |
| venue: IEEE Transactions / Journals | 1.787 | 0.000 | 496.877 |
| venue: Open-access mega-journals | 1.051 | 0.000 | 186.013 |
| venue: Other venue | -1.034 | 0.000 | -64.453 |
| discipline: Life & environmental sciences | 0.132 | 0.000 | 14.083 |
| discipline: Management, economics & finance | -0.255 | 0.000 | -22.480 |
| discipline: Medicine & health | 0.002 | 0.913 | 0.226 |
| discipline: Other or unclassified | -0.059 | 0.032 | -5.733 |
| discipline: Physical sciences & mathematics | 0.189 | 0.000 | 20.827 |
| discipline: Social sciences & education | -0.484 | 0.000 | -38.352 |
| age | 0.082 | 0.000 | 8.594 |
| review | 0.504 | 0.000 | 65.595 |
| title_words | 0.025 | 0.000 | 2.502 |
| title_colon | 0.127 | 0.000 | 13.516 |
Step 5: See the effects in a coefficient plot
A coefficient plot shows each effect and its uncertainty in one picture.
ci = model.conf_int()
ci.index = [tidy(i) for i in ci.index]
show = [i for i in table.index if i.startswith("venue: ")] + ["review", "title_colon"]
pct = (np.exp(table.loc[show, "coef"]) - 1) * 100
low = (np.exp(ci.loc[show, 0]) - 1) * 100
high = (np.exp(ci.loc[show, 1]) - 1) * 100
fig, ax = plt.subplots(figsize=(8, 4))
ax.errorbar(pct, range(len(show)), xerr=[pct - low, high - pct], fmt="o", color="green")
ax.axvline(0, color="grey")
ax.set_yticks(range(len(show)), show)
ax.set_xlabel("% change in citations (95% confidence interval)")
ax.invert_yaxis()
plt.tight_layout()
plt.show()Types of regression
| Type | Outcome | Example |
|---|---|---|
| Simple linear | Numeric, one predictor | Age → log citations |
| Multiple linear | Numeric, several predictors | Age, venue, review, title → log citations |
| Logistic | Yes/no | Factors → whether a paper is cited at all |
| Poisson / negative binomial | Counts | Factors → number of citations |
How to run a regression
- Choose the outcome and predictors from your research question and theory.
- Look at the data first: skew, outliers and the shape of relationships; transform if needed.
- Fit the model in Python (statsmodels), R, SPSS or Stata.
- Check the assumptions: linearity, independent errors, constant spread of residuals (see heteroskedasticity), and no extreme multicollinearity.
- Report coefficients with confidence intervals and p-values, R² and the sample size, and explain them in plain words.
Common mistakes reviewers point out
- Interpreting coefficients as causes in observational data.
- Using linear regression for a yes/no outcome instead of logistic regression.
- Modelling skewed outcomes without a transformation or a suitable model.
- Forgetting the reference group when interpreting category coefficients.
Frequently asked questions
What is regression analysis used for?
It is used to estimate how an outcome changes with one or more predictors, to compare the effects of several factors at once, and to make predictions.
What does a regression coefficient mean?
It is the expected change in the outcome for a one-unit increase in that predictor, with all other predictors held constant.
Why use the logarithm of the outcome?
When an outcome such as citations or income is heavily skewed, its logarithm is closer to normal, which makes linear regression fit better. Coefficients then describe percentage changes.
What is a good R² value?
It depends on the field. In physical experiments R² is often high; for outcomes like citations, values below 0.3 are common and can still be meaningful.
How do I run a regression in Python?
Use the statsmodels library, for example smf.ols(“y ~ x1 + x2”, data=df).fit(), as shown in the notebook on this page.
Use this data in your own work
ScholarsColab (2026). ScholarsColab Research Methods Index [Data set]. Vidhilekha Soft Solutions Pvt Ltd. Retrieved 15 October 2026, from https://scholarscolab.in/research-methodology/. Licensed under CC BY 4.0.Download the data (CSV) →Need help applying this to your research?
Discuss your research problem with a PhD mentor, hand the whole project to a research project manager, or post your project and let matched experts apply.
Mentors whose published work uses this approach:

Dr Uma Mahesh R Ndr.umamaheshrn.ci@atme.edu.in
S.K AgarwalThapar University
Dr. Vikash YadavGovernment Polytechnic Bighapur Unnao
Tarek Abd El-HafeezMinia University