Build regression model

Simple Linear Regression with R
R PROGRAMMING • REGRESSION PRACTICAL

Simple Linear
Regression with R

Build, interpret, evaluate and diagnose a regression model that predicts house price from house area.

Explore → Model → Interpret → Predict → Diagnose

Download the practice dataset

The dataset contains 40 houses with area measured in square feet and price measured in lakh. Values include realistic variation around an increasing linear relationship.

Only the CSV dataset is downloadable from this article.

Before running R: save the CSV in the active R working directory or supply its complete path to read.csv().

1. Import and inspect the dataset

# Display the current working directory
getwd()

# Optional: choose the directory containing the CSV
# setwd("D:/R_Practical")

# Import data
houses <- read.csv(
  "house_area_price.csv",
  stringsAsFactors = FALSE
)

# Inspect data
head(houses)
tail(houses)
dim(houses)
names(houses)
str(houses)
summary(houses)

Inspection confirms that Area_sqft and Price_Lakh are numerical and that each row represents one house. The identifier House_ID labels observations but should not be used as a numerical predictor.

# Check data quality
colSums(is.na(houses))
sum(duplicated(houses$House_ID))

# Retain valid observations for modelling
model_data <- houses[
  complete.cases(
    houses[c("Area_sqft", "Price_Lakh")]
  ),
]

2. Explore the relationship before modelling

A scatter plot reveals direction, approximate form, unusual observations and possible changes in spread. A linear model is plausible when the cloud of points follows a roughly straight pattern.

plot(
  model_data$Area_sqft,
  model_data$Price_Lakh,
  main = "House Area and Price",
  xlab = "Area (square feet)",
  ylab = "Price (lakh)",
  pch = 19,
  col = "#1769FF"
)

Correlation

correlation <- cor(
  model_data$Area_sqft,
  model_data$Price_Lakh,
  method = "pearson"
)

print(correlation)

Pearson correlation ranges from −1 to +1. A positive value indicates that larger areas tend to be associated with higher prices. A value close to ±1 indicates a strong linear association, while a value near zero indicates weak linear association.

Correlation caution: a high correlation does not guarantee that a linear model is appropriate. Always inspect the scatter plot for curvature, clusters, influential points and changing variance.

3. Fit the regression model using lm()

R's lm() function fits linear models. The formula places the response on the left and the predictor on the right.

price_model <- lm(
  Price_Lakh ~ Area_sqft,
  data = model_data
)

print(price_model)
summary(price_model)

The model estimates the intercept and slope by ordinary least squares, selecting the line that minimizes the sum of squared residuals.

Residual = Observed value − Predicted value
# Extract coefficients
coefficients <- coef(price_model)
intercept <- coefficients[1]
slope <- coefficients[2]

print(intercept)
print(slope)

4. Interpret the regression coefficients

Intercept

The intercept is the predicted house price when area equals zero. Because a zero-square-foot house is outside the useful data range, the intercept mainly positions the regression line and may not have a meaningful real-world interpretation.

Slope

The slope estimates the expected change in house price for every additional square foot of area. If the fitted slope is 0.05, then an increase of 100 square feet corresponds to an estimated price increase of:

0.05 × 100 = 5 lakh
price_change_for_100_sqft <- slope * 100
print(price_change_for_100_sqft)
Interpret within range: the dataset covers areas from 650 to 2600 square feet. Predictions far outside this interval are extrapolations and may be unreliable.

5. Understand the model summary

summary(price_model) reports coefficient estimates, standard errors, t statistics, p-values, residual information, residual standard error, R², adjusted R² and the overall F test.

OutputMeaningInterpretation
EstimateFitted intercept or slopeMagnitude and direction of the relationship
Std. ErrorEstimated uncertainty of a coefficientSmaller values imply more precise estimates, relative to scale
t valueEstimate divided by standard errorEvidence against a zero coefficient
Pr(>|t|)Coefficient p-valueSmall values indicate evidence of a non-zero linear association under model assumptions
Residual standard errorTypical residual size in response unitsApproximate unexplained prediction error in lakh
Multiple R-squaredProportion of response variance explainedHigher values indicate closer in-sample fit
F-statisticOverall model testFor one predictor, it tests the same null slope as the coefficient t test
Statistical significance is not practical significance. A small p-value does not tell whether the estimated change is important for the business or decision context.

6. Draw the fitted regression line

plot(
  model_data$Area_sqft,
  model_data$Price_Lakh,
  main = "Simple Linear Regression: Area vs Price",
  xlab = "Area (square feet)",
  ylab = "Price (lakh)",
  pch = 19,
  col = "#1769FF"
)

abline(
  price_model,
  col = "#FF6B57",
  lwd = 3
)

legend(
  "topleft",
  legend = c("Observed houses", "Regression line"),
  col = c("#1769FF", "#FF6B57"),
  pch = c(19, NA),
  lty = c(NA, 1),
  lwd = c(NA, 3),
  bty = "n"
)

Vertical distances from the points to the line are residuals. Points above the line have positive residuals because observed price exceeds predicted price; points below the line have negative residuals.

7. Generate fitted values and residuals

model_data$Predicted_Price <- fitted(
  price_model
)

model_data$Residual <- residuals(
  price_model
)

head(
  model_data[
    c(
      "House_ID",
      "Price_Lakh",
      "Predicted_Price",
      "Residual"
    )
  ]
)

Fitted values describe the model's in-sample estimates. Residuals are essential for diagnostics because they reveal patterns not captured by the fitted line.

8. Evaluate model accuracy

R² measures explained variation, while MAE and RMSE express prediction error in the original response unit.

actual <- model_data$Price_Lakh
predicted <- predict(price_model)

mae <- mean(abs(actual - predicted))
mse <- mean((actual - predicted)^2)
rmse <- sqrt(mse)
r_squared <- summary(price_model)$r.squared

accuracy <- c(
  MAE = mae,
  MSE = mse,
  RMSE = rmse,
  R_Squared = r_squared
)

round(accuracy, 4)
MetricMeaningPreferred direction
MAEAverage absolute prediction errorLower is better
MSEAverage squared prediction errorLower is better
RMSESquare root of MSE, expressed in lakhLower is better
Fraction of price variance explained by areaCloser to 1 indicates stronger in-sample fit

These in-sample measures evaluate the same data used to fit the model and may be optimistic. Prediction for new cases should be evaluated using held-out data or cross-validation.

9. Predict price for new houses

new_houses <- data.frame(
  Area_sqft = c(1250, 1750, 2250)
)

point_predictions <- predict(
  price_model,
  newdata = new_houses
)

cbind(new_houses, point_predictions)

Confidence interval for the mean response

predict(
  price_model,
  newdata = new_houses,
  interval = "confidence",
  level = 0.95
)

A confidence interval estimates the mean price for houses at a specified area.

Prediction interval for an individual house

predict(
  price_model,
  newdata = new_houses,
  interval = "prediction",
  level = 0.95
)

A prediction interval is wider because it includes uncertainty about both the regression line and the variation among individual houses.

10. Check regression assumptions

LinearityThe average relationship between area and price is approximately straight.
IndependenceErrors from different observations are independent.
Constant varianceResidual spread is reasonably stable across fitted values.
Residual normalityResiduals are approximately normal for reliable small-sample inference.
No extreme influenceNo single observation controls the fitted line disproportionately.
Correct specificationA one-predictor linear model is suitable for the purpose.

Standard diagnostic plots

par(mfrow = c(2, 2))
plot(price_model)
par(mfrow = c(1, 1))
Diagnostic plotWhat to examine
Residuals vs FittedNo systematic curve and roughly constant vertical spread
Normal Q–QResidual points approximately follow the reference line
Scale–LocationSimilar residual spread across fitted values
Residuals vs LeveragePotential influential observations and Cook's distance
# Additional influence measures
cooks_distance <- cooks.distance(price_model)
which(cooks_distance > 4 / nrow(model_data))

# Largest absolute studentized residuals
studentized <- rstudent(price_model)
order(abs(studentized), decreasing = TRUE)[1:5]
Do not delete automatically: an influential observation may be a data error, a legitimate unusual case or evidence that the model is incomplete. Investigate its meaning before changing the dataset.

11. Optional train–test evaluation using base R

A train–test split gives a more realistic estimate of performance on unseen observations. A fixed seed makes the split reproducible.

set.seed(42)

train_index <- sample(
  seq_len(nrow(model_data)),
  size = floor(0.80 * nrow(model_data))
)

train_data <- model_data[train_index, ]
test_data <- model_data[-train_index, ]

train_model <- lm(
  Price_Lakh ~ Area_sqft,
  data = train_data
)

test_predictions <- predict(
  train_model,
  newdata = test_data
)

test_mae <- mean(
  abs(test_data$Price_Lakh - test_predictions)
)

test_rmse <- sqrt(
  mean(
    (test_data$Price_Lakh - test_predictions)^2
  )
)

print(c(Test_MAE = test_mae, Test_RMSE = test_rmse))

With only 40 records, test results depend noticeably on which observations enter the test set. Repeated cross-validation is generally more stable, but the split above demonstrates the essential separation between training and evaluation.

Interpretation and reporting template

  1. State the predictor, response, sample size and units.
  2. Describe the scatter plot and report Pearson correlation.
  3. Write the fitted equation using the estimated intercept and slope.
  4. Interpret the slope in meaningful units, such as price change per 100 square feet.
  5. Report the slope estimate, uncertainty and p-value.
  6. Report R² together with MAE or RMSE.
  7. Discuss residual diagnostics and influential observations.
  8. Separate interpolation from extrapolation.
  9. State that association does not establish causation.
  10. Recognize omitted predictors such as location, age, quality and amenities.

Practice questions

  1. Calculate the Pearson correlation between area and price.
  2. Write the fitted regression equation from the model coefficients.
  3. Interpret the slope per one square foot and per 100 square feet.
  4. Predict price for houses of 1400, 1900 and 2400 square feet.
  5. Compare confidence intervals with prediction intervals.
  6. Identify the observation with the largest absolute residual.
  7. Identify houses whose Cook's distance exceeds 4/n.
  8. Perform an 80:20 train–test split and report test MAE and RMSE.
  9. Explain why high R² does not prove causation.
  10. Suggest variables needed for a more realistic multiple-regression model.
R Practical • Simple Linear Regression • Prediction and Diagnostics