Regression Analysis Explained: Coefficients, R² and a Real Example

Home › Research Methodology › Regression Analysis Explained

Quick answerRegression analysis estimates how an outcome (the dependent variable) changes when one or more predictors (independent variables) change. Its main advantage over a simple comparison is that it can look at several factors at once, showing each one’s effect while holding the others constant.

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

In [1]:
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()
Out [1]:
(41792, 15)
yearcitationsvenue_typevenue_grouptitle_wordstitle_colonreviewsystematicmachine_learningdeep_learningiotblockchaincovidsustainabilitydiscipline
02023.031journalOther journals12000000000Medicine & health
12024.024journalOther journals13000110000Medicine & health
22024.012journalOther journals16000000000Medicine & health
32024.09journalOther journals20010000000Medicine & health
42024.09journalGeneric "International Journal of"9000000000Medicine & 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.

In [2]:
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)
Out [2]:
agecitationslog_citations
count39348.0039348.0039348.00
mean6.5425.821.73
std5.55236.461.54
min0.000.000.00
25%2.000.000.00
50%5.004.001.61
75%9.0016.002.83
max30.0019177.009.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?

In [3]:
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()
Out [3]:
log_citations = 1.235 + 0.076 × age   (R² = 0.075)
Scatter plot0.001.663.2124.8186.4248.030fitted lineAge of paper (years)log(1 + citations)
Each dot is one paper (a sample of about 2,000); the green line is the fitted regression line.
How to read it: each dot is a paper; the green line is the best straight line through them. Each extra year of age adds 0.076 to log citations, about 7.9% more citations. R² is 0.075: age alone explains about 7.5% of the variation, so papers of the same age still differ enormously.

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.

In [4]:
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)
Out [4]:
R² = 0.179, n = 39,348
coefp-value% change in citations
venue: Conference-0.3900.000-32.272
venue: Generic "International Journal of"-0.3080.000-26.521
venue: IEEE Transactions / Journals1.7870.000496.877
venue: Open-access mega-journals1.0510.000186.013
venue: Other venue-1.0340.000-64.453
discipline: Life & environmental sciences0.1320.00014.083
discipline: Management, economics & finance-0.2550.000-22.480
discipline: Medicine & health0.0020.9130.226
discipline: Other or unclassified-0.0590.032-5.733
discipline: Physical sciences & mathematics0.1890.00020.827
discipline: Social sciences & education-0.4840.000-38.352
age0.0820.0008.594
review0.5040.00065.595
title_words0.0250.0002.502
title_colon0.1270.00013.516
How to read it: because the outcome is a logarithm, the last column turns each coefficient into a percentage change in citations. Venue groups are compared with “Other journals”, and disciplines with Engineering & computer science. With all these factors, R² rises from 0.075 to 0.179, about 2.4 times as much as age alone.

Step 5: See the effects in a coefficient plot

A coefficient plot shows each effect and its uncertainty in one picture.

In [5]:
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()
Out [5]:
Effect of each factor on citations-100%0%+100%+200%+300%+400%+500%+600%venue: Conference-32%venue: Generic "International Journal of"-27%venue: IEEE Transactions / Journals+497%venue: Open-access mega-journals+186%venue: Other venue-64%review+66%title_colon+14%Change in citations compared with the reference group, with 95% confidence interval
Each dot is the estimated effect of one factor, holding all the others constant; the line is its 95% confidence interval. Venue groups are compared with "Other journals".
What it tells us: holding everything else constant, papers in “IEEE Transactions / Journals” have about +497% citations compared with other journals; review articles +66% compared with original papers; and a colon in the title +14%. Where a paper is published is associated with far larger differences than title features.
Association, not cause. This model describes patterns in published papers. A paper in a top venue may be cited more partly because stronger work is sent there; adding a colon to your title will not guarantee more citations.
Run this analysis yourself. Download the notebook and open it in Jupyter or Google Colab (File → Upload notebook). It loads the same anonymised ScholarsColab data, so your results will match this page.Download notebook (.ipynb) →Data files: papers.csv · mentors.csv

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

  1. Choose the outcome and predictors from your research question and theory.
  2. Look at the data first: skew, outliers and the shape of relationships; transform if needed.
  3. Fit the model in Python (statsmodels), R, SPSS or Stata.
  4. Check the assumptions: linearity, independent errors, constant spread of residuals (see heteroskedasticity), and no extreme multicollinearity.
  5. 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

Use this data in your own research. Download the aggregated figures behind these charts (counts, medians and shares by type of paper, period, method and discipline) as a CSV file. Please cite it as: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:

More research methodology guides

About the data on this page. The ScholarsColab Research Methods Index is built from the Google Scholar publication lists of PhD researchers who mentor on ScholarsColab, and is updated daily as mentors and publications are added. Methods, designs and paper types are identified from titles, so papers whose titles do not mention them are not counted in those groups. The mentors are not a random sample of all researchers (engineering and computer science are strongly represented), so the figures describe this group of researchers and may not apply to research as a whole.