house_price_inspection

mttlong / house_price_inspection

A local file has been selected for analysis:
"/Users/marklong/learning/UOM/bitbucket/miniproject1/code/Week_11_Graded_Mini_Project_Dataset_houseprice.csv"

Load and inspect this file now.

I'll load the selected CSV file and show a quick preview.

</>Load house price data
import pandas as pd

file_path = "/Users/marklong/learning/UOM/bitbucket/miniproject1/code/Week_11_Graded_Mini_Project_Dataset_houseprice.csv"
df = pd.read_csv(file_path)

print(f"Shape: {df.shape}")
columns = df.columns.tolist()
print(f"Columns ({len(columns)}):", columns if len(columns) <= 100 else columns[:100] + ["..."])

df.head()
Shape: (1460, 81)
Columns (81): ['Id', 'MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea', 'Street', 'Alley', 'LotShape', 'LandContour', 'Utilities', 'LotConfig', 'LandSlope', 'Neighborhood', 'Condition1', 'Condition2', 'BldgType', 'HouseStyle', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd', 'RoofStyle', 'RoofMatl', 'Exterior1st', 'Exterior2nd', 'MasVnrType', 'MasVnrArea', 'ExterQual', 'ExterCond', 'Foundation', 'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinSF1', 'BsmtFinType2', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', 'Heating', 'HeatingQC', 'CentralAir', 'Electrical', '1stFlrSF', '2ndFlrSF', 'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath', 'HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'KitchenQual', 'TotRmsAbvGrd', 'Functional', 'Fireplaces', 'FireplaceQu', 'GarageType', 'GarageYrBlt', 'GarageFinish', 'GarageCars', 'GarageArea', 'GarageQual', 'GarageCond', 'PavedDrive', 'WoodDeckSF', 'OpenPorchSF', 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'PoolQC', 'Fence', 'MiscFeature', 'MiscVal', 'MoSold', 'YrSold', 'SaleType', 'SaleCondition', 'SalePrice']
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities ... PoolArea PoolQC Fence MiscFeature MiscVal MoSold YrSold SaleType SaleCondition SalePrice
0 1 60 RL 65.0 8450 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 2 2008 WD Normal 208500
1 2 20 RL 80.0 9600 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 5 2007 WD Normal 181500
2 3 60 RL 68.0 11250 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 9 2008 WD Normal 223500
3 4 70 RL 60.0 9550 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 2 2006 WD Abnorml 140000
4 5 60 RL 84.0 14260 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 12 2008 WD Normal 250000

5 rows × 81 columns

The file contains 1,460 property records and 81 columns, matching a typical house-price modeling dataset. It includes a unique Id field, numerical home and lot characteristics, categorical features such as neighborhood and zoning, and substantial missingness in some optional-property fields (for example, Alley, pool-related fields, and fence-related fields) as visible in the preview.

The first rows show mixed data types and variables covering location, lot dimensions, construction quality, living area, basement, bathrooms, garage, and sale timing—suitable for house-price analysis.

Do an EDA on this dataset

Thinking

Considering EDA steps

I need to choose the first step for exploratory data analysis (EDA). It makes sense to start with a data quality overview, focusing on missing values and types, along with a summary of targets. I could create a compact table showing data types and missing values, while avoiding initial inspection. I'll generate a summary DataFrame to highlight the primary missing data, since the user wants a general and iterative approach to EDA. I'll start with the missing data profile.

Start with data completeness: this identifies fields that need cleaning or special handling before deeper price analysis.

</>Summarize missing values
missing = (
    df.isna()
    .sum()
    .to_frame("missing_count")
    .assign(missing_pct=lambda x: (x["missing_count"] / len(df) * 100).round(1))
    .query("missing_count > 0")
    .sort_values("missing_count", ascending=False)
)

missing
missing_count missing_pct
PoolQC 1453 99.5
MiscFeature 1406 96.3
Alley 1369 93.8
Fence 1179 80.8
MasVnrType 872 59.7
FireplaceQu 690 47.3
LotFrontage 259 17.7
GarageType 81 5.5
GarageYrBlt 81 5.5
GarageFinish 81 5.5
GarageQual 81 5.5
GarageCond 81 5.5
BsmtFinType2 38 2.6
BsmtExposure 38 2.6
BsmtFinType1 37 2.5
BsmtCond 37 2.5
BsmtQual 37 2.5
MasVnrArea 8 0.5
Electrical 1 0.1

Several columns have missing values that are likely structural, meaning the feature does not apply rather than being an unknown value. This is especially clear for PoolQC (99.5%), MiscFeature (96.3%), Alley (93.8%), and Fence (80.8%). FireplaceQu is absent for nearly half of homes, plausibly because many homes lack fireplaces. Garage-related columns share exactly 81 missing records, suggesting those properties have no garage.

LotFrontage has 17.7% missingness and likely needs statistical imputation rather than a “None” category. Only Electrical has a single missing record, while basement and masonry measurements have relatively limited missingness.

Next, summarize the sale-price target and identify its strongest numerical relationships.

</>Show sale price summary
numeric_summary = df.select_dtypes(include="number").corr(numeric_only=True)["SalePrice"].sort_values()

display(df["SalePrice"].describe().to_frame("SalePrice"))
display(numeric_summary.tail(11).to_frame("correlation_with_SalePrice"))
SalePrice
count 1460.000000
mean 180921.195890
std 79442.502883
min 34900.000000
25% 129975.000000
50% 163000.000000
75% 214000.000000
max 755000.000000
correlation_with_SalePrice
YearRemodAdd 0.507101
YearBuilt 0.522897
TotRmsAbvGrd 0.533723
FullBath 0.560664
1stFlrSF 0.605852
TotalBsmtSF 0.613581
GarageArea 0.623431
GarageCars 0.640409
GrLivArea 0.708624
OverallQual 0.790982
SalePrice 1.000000

Sale prices are right-skewed: the median is 163,000 USD, below the mean of 180,921 USD, with a wide range from 34,900 USD to 755,000 USD. This suggests a small number of high-priced homes may influence averages and modeling.

The strongest numeric relationships with price are:

  • OverallQual ($r=0.791$): overall construction/material quality is the clearest price driver.
  • GrLivArea ($r=0.709$): larger above-ground living space is strongly associated with higher prices.
  • Garage capacity and area ($r=0.640$ and $r=0.623$), basement area ($r=0.614$), and first-floor area ($r=0.606$) are also important.
  • Newer or recently remodeled homes tend to sell for more (YearBuilt, $r=0.523$; YearRemodAdd, $r=0.507$).

Missingness is concentrated in amenity fields. PoolQC, MiscFeature, Alley, and Fence are missing for most homes, likely indicating the amenity is absent. Garage fields are jointly missing for 81 properties, consistent with homes without garages. LotFrontage has meaningful missingness (17.7%) and should be imputed carefully if used in modeling.

A useful remaining EDA view is how sale price varies across the highest-impact categorical feature, overall quality.

</>Plot sale price by quality
import seaborn as sns
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 5))
sns.boxplot(data=df, x="OverallQual", y="SalePrice", color="#72a6c7")
plt.title("Sale Price by Overall Quality")
plt.xlabel("Overall Quality")
plt.ylabel("Sale Price (USD)")
plt.ticklabel_format(style="plain", axis="y")
plt.show()
Notebook output

The price distribution and correlations provide a strong initial view of numeric drivers, but the latest quality chart has no visible summary values. The table below quantifies the median sale price and sample size at each quality level, allowing the pattern to be interpreted reliably.

</>Summarize sales by quality
quality_summary = (
    df.groupby("OverallQual")["SalePrice"]
    .agg(homes="size", median_sale_price="median", mean_sale_price="mean")
    .round(0)
)

quality_summary
homes median_sale_price mean_sale_price
OverallQual
1 2 50150.0 50150.0
2 3 60000.0 51770.0
3 20 86250.0 87474.0
4 116 108000.0 108421.0
5 397 133000.0 133523.0
6 374 160000.0 161603.0
7 319 200141.0 207716.0
8 168 269750.0 274736.0
9 43 345000.0 367513.0
10 18 432390.0 438588.0
Made with MLJAR
Explore more conversationsMore from mttlong