...
Interactive Map For Single and Double Storey Terraced Property Sale For 2022 In Melaka Project Overview This project proposes the creation of an interactive map that will contain detailed information about all the single storey and double storey terraced properties sold in Melaka in 2022. The map will serve as a tool for housing developers to develop effective pricing and business strategies for future developments in Melaka, taking into account the current market dynamics. In 2022, a total of 2870 transactions were made for single storey and double storey terraced houses in Melaka. The property sales for these houses amounted to RM869,477,476.00. These transactions include both freehold and leasehold properties, and cover 457 areas or schemes located in three districts Melaka Tengah, Alor Gajah, and Jasin. The property market in the state is anticipated to maintain its upward trend, bolstered by the upcoming development projects. These include the Melaka Waterfront Economic Zone (MWEZ) with an expected completion date of 2035, and the ongoing construction of Harbour City Melaka by Hatten Land Ltd. These initiatives are set to have a positive impact on the state's property market. Terraced Property Outlook The property market in Melaka is interesting to watch with the launch of two exciting residential projects: Scientex Durian Tunggal 2 and Bandar Botani Parkland. These developments, spanning 202 acres of land, offer single and double storey terraced homes, making them a prime choice for homebuyers seeking quality living spaces. Keep an eye on these segments, as they are likely to be in high demand in the near future. Code and Resources Used
• Jupyter Notebook Version: 6.5.4
• Packages: pandas, numpy, scipy, matplotlib, seaborn, plotly express, sklearn, dataframe_image
• Dataset Source: https://napic2.jpph.gov.my/ms/data-transaksi?category=36&id=241 Dataset Information
•'dataset_2022.csv' contains data from National Property Information Centre (NAPIC).
•'latlong.csv' contains latitude and longitude information for scheme name/area. This lat and long information were built from https://postcode.my/location/melaka/ based on scheme name/area from dataset_2022.
•'melaka_terraced_property_sales_2022.csv' contains data generated from Jupyter Notebook following cleaning processes. 1. Data Cleaning In this part, we will begin our exploratory data analysis (EDA) by viewing the dataset_2022.csv. Setup Data Overview Check the columns type Check missing values Based from the dataset, there is no missing values. Data Cleaning 2870 rows × 10 columns We have observed that the dataset expresses the 'Land Area' and 'Main Floor Area' in square meters (sq. meter). Although it is sufficient for performing exploratory data analysis, it is worth noting that square feet measurement is the most commonly used nomenclature in the real estate market to represent the size of a property. We have convert the Land Area and Main Floor Area into square feet (sq.ft). Furthermore, we can conveniently rename the Land Area to Land Size and the Main Floor Area to Build Size. Moreover, we have successfully transformed the column 'Month, Year of Transaction Date' into a date column. 2870 rows × 10 columns 2870 rows × 10 columns 2870 rows × 10 columns Latitude and Longitude Positions Before creating an interactive map, it is necessary to acquire the approximate latitude and longitude positions for each scheme name/area. As these positions are not included in the dataset, we can obtain them through the integration API between portal postcode.my and Google Maps. 2870 rows × 3 columns The portal provides access to 457 scheme names/areas, which can be leveraged to generate positions. However, the original dataset requires the integration of latitude and longitude positions to facilitate this process. 2870 rows × 2 columns 2870 rows × 12 columns 2870 rows × 12 columns 🔶 Insights: We have combined the latitude and longitute into the dataset_2022.csv and renamed it to melaka_terraced_property_sales_2022.csv. Let's explore Melaka Property Sales Year 2022 with useful statistics, now that the dataset has been processed to the desired format. 2.0 Data Visualizations Statistics Based on the statistics summary provided, it appears that there were a total of 2,870 transactions in 2022. The highest transaction price was RM1.2 million, while the lowest was RM90,000.00. The average transaction price comes in at RM302,953.82. As the dataset pertains to both single storey and double storey terraced houses, it may be helpful to visualize the information according to each property type. Boxplots The boxplots depicted above showcase the various property types segregated by districts. Additionally, the boxplots also portray the single storey and double storey terraced houses based on their land status, be it Freehold or Leasehold. Despite the presence of outliers in the boxplots, we have decided to include them for better visualization on the map. Heatmap of Property Type vs District The heatmap displayed above provides a comparison of property types and districts. In 2022, Melaka Tengah had the highest number of single storey terraced houses sold with 969 units, while Jasin had 471 units and Alor Gajah had 375 units. On the other hand, Melaka Tengah also had the highest number of double storey terraced houses sold with 646 units, followed by Alor Gajah with 313 units and Jasin with 96 units. In total, single storey terraced houses were sold more frequently with 1815 units compared to double storey terraced houses with 1055 units. Heatmap of District vs Tenure Looking at the heatmap charting district against tenure, it's clear that the largest number of transactions took place in Melaka Tengah, where 1615 units were sold. Alor Gajah saw the second-highest number of transactions at 688 units, followed by Jasin at 567 units. In terms of tenure, it seems that freehold properties were the most popular, with 1633 transactions, including 854 from Melaka Tengah, 468 from Jasin, and 311 from Alor Gajah. Leasehold residentials, on the other hand, saw 1237 transactions, including 761 units from Melaka Tengah, 256 from Jasin, and 220 from Alor Gajah. Interactive Map Map 1: Hotspots for overall locations From the latitude and longitude information, we can create a scatter plot using the plotly.express package to visualize the approximate positions of each scheme name/area. While the interactive features are not available here, running the codes can be quite intriguing. You can gather some information simply by hovering over the map. From the figure above, we can see that the yellow circle represents a higher transaction price and is easily located on the map. The position of the yellow circle represents the location of the highest value transaction in Taman Residence Lapan, Melaka Tengah. Map 2: Hotspots for overall transactions The most concentrated dots are located in Melaka Tengah, which is near the central business district (CBD), followed by Bandar Botani Parkland with 124 transactions in 2022. The highest number of transactions (154) were recorded in Taman Scientex (Bukit Tambun Perdana) in proximity to Durian Tunggal and Alor Gajah. Map 3: Hotspots for Single Storey Locations Figure above displays the locations for every single storey terraced sold in 2022. Ideally, Melaka Tengah seems to be very active in terms of populated dots on the map. Map 4: Hotspots for Single Storey Transactions However, records show that Jasin was attractive enough to pull homebuyers in 2022. The transactions count were recorded at 124 in Botani Parkland alone. Additionally, high value residential such Country Villa in Jasin was also contributing atleast 44 transactions. Map 5: Hotspots for Double Storey Locations In 2022, 1085 units of double storey terraced were sold in Melaka. Although Taman Anggerik (Lot 71) in Melaka Tengah recorded the highest market value for double storey of RM390,000.00 but it has serious contender from Jasin which is Country Villas at RM380,000.00. Both the residentials have almost identical build size of 1537.95 and 1471.75 respectively. Map 6: Hotspots for Double Storey Transactions Nevertheless, Alor Gajah seems has stole a spotlight since the highest transactions count was recorded in Taman Scientex (Bukit Tambun Perdana). The new development in Alor Gajah has managed to attract homebuyers to settle in the district. 3. The Insights Regression Analysis Based on the density plot shown above, it's clear that the majority of transactions fall within the price range of RM200,000.00 to RM300,000.00. Additionally, the graph highlights that the density of build size is concentrated between 800 sq.ft and 900 sq.ft. These patterns suggest a high demand for residential properties within this specific price and build size range. By utilizing a linear regression model and the sklearn.linear_model package, we were able to calculate the coefficients for both dependent and independent variables. The computed results are as follows: Coefficient - [195.0251, 55.3691] and Intercept - 12227.5884.
Thus, the regression can be represent as in the model below: The MLR model is
$$Y = \beta_0 + \beta_1 X_1 + \beta_2 X_2$$ Recommendations Utilize Interactive Map for Market Analysis Housing developers should leverage the interactive map to conduct in-depth market analysis by exploring transaction patterns, pricing trends and demand hotspots across different scheme name/areas in Melaka. This will facilitate informed decision-making in formulating pricing strategies and identifying lucrative development opportunities. Monitor Future Development Projects Given the anticipated growth momentum in Melaka's property market, it's crucial for developers to closely monitor upcoming development projects such as Melaka Waterfront Economic Zone (MWEZ) and Harbour City Melaka. These projects are expected to drive demand and reshape the landscape of the property market, presenting potential investment opportunities. Adapt Business Strategies Based on the insights derived from the interactive map and market analysis, housing developers should adapt their business strategies accordingly. This may involve diversifying product offerings, targeting specific customer segments, or adjusting pricing strategies to remain competitive in the dynamic market landscape. Enhance Customer Engagement The interactive map can also serve as a valuable tool for enhancing customer engagement and marketing efforts. Developers can leverage the map to provide potential buyers with detailed information about available properties, amenities and surrounding infrastructure, thereby improving transparency and fostering trust with customers. Collaborate with Stakeholders Collaboration with local authorities, real estate agencies and other stakeholders can further enhance the effectiveness of the interactive map and promote sustainable growth in the property market. By sharing data and insights, stakeholders can collectively address challenges, identify opportunities and contribute to the overall development of Melaka's property sector. Conclusion In conclusion, the development of an interactive map for single and double storey terraced property sales in Melaka for the year 2022 offers valuable insights and opportunities for housing developers. A comprehensive dataset covering transaction details, property attributes and geographic information, developers can gain a deeper understanding of market dynamics and consumer preferences. The analysis revealed that Melaka's property market recorded significant transactions in 2022, with single and double storey terraced properties accounting for a substantial portion of the market activity. Key insights such as pricing trends, demand hotspots and upcoming development projects provide developers with actionable information to formulate effective business strategies and capitalize on emerging opportunities. Moving forward, it is recommended that developers leverage the interactive map to conduct detailed market analysis, monitor future development projects, adapt business strategies, enhance customer engagement and collaborate with stakeholders. By doing so, developers can navigate the evolving property landscape in Melaka and drive sustainable growth in the industry.from IPython.display import display, Image
display(Image(filename='C:/Users/KEMAS/myproject/MWEZ.png'))
import numpy as np
import pandas as pd
import os
import warnings
warnings.filterwarnings("ignore")
!pip install dataframe_image
import dataframe_image as dfi
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: dataframe_image in c:\users\kemas\appdata\roaming\python\python311\site-packages (0.2.3)
Requirement already satisfied: pandas>=0.24 in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (2.0.3)
Requirement already satisfied: nbconvert>=5 in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (6.5.4)
Requirement already satisfied: aiohttp in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (3.8.5)
Requirement already satisfied: requests in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (2.31.0)
Requirement already satisfied: pillow in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (10.0.1)
Requirement already satisfied: packaging in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (23.1)
Requirement already satisfied: mistune in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (0.8.4)
Requirement already satisfied: lxml in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (4.9.3)
Requirement already satisfied: beautifulsoup4 in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (4.12.2)
Requirement already satisfied: cssutils in c:\users\kemas\appdata\roaming\python\python311\site-packages (from dataframe_image) (2.10.2)
Requirement already satisfied: html2image in c:\users\kemas\appdata\roaming\python\python311\site-packages (from dataframe_image) (2.0.4.3)
Requirement already satisfied: bleach in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (4.1.0)
Requirement already satisfied: defusedxml in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (0.7.1)
Requirement already satisfied: entrypoints>=0.2.2 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (0.4)
Requirement already satisfied: jinja2>=3.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (3.1.2)
Requirement already satisfied: jupyter-core>=4.7 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (5.3.0)
Requirement already satisfied: jupyterlab-pygments in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (0.1.2)
Requirement already satisfied: MarkupSafe>=2.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (2.1.1)
Requirement already satisfied: nbclient>=0.5.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (0.5.13)
Requirement already satisfied: nbformat>=5.1 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (5.9.2)
Requirement already satisfied: pandocfilters>=1.4.1 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (1.5.0)
Requirement already satisfied: pygments>=2.4.1 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (2.15.1)
Requirement already satisfied: tinycss2 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (1.2.1)
Requirement already satisfied: traitlets>=5.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (5.7.1)
Requirement already satisfied: python-dateutil>=2.8.2 in c:\programdata\anaconda3\lib\site-packages (from pandas>=0.24->dataframe_image) (2.8.2)
Requirement already satisfied: pytz>=2020.1 in c:\programdata\anaconda3\lib\site-packages (from pandas>=0.24->dataframe_image) (2023.3.post1)
Requirement already satisfied: tzdata>=2022.1 in c:\programdata\anaconda3\lib\site-packages (from pandas>=0.24->dataframe_image) (2023.3)
Requirement already satisfied: numpy>=1.21.0 in c:\programdata\anaconda3\lib\site-packages (from pandas>=0.24->dataframe_image) (1.24.3)
Requirement already satisfied: attrs>=17.3.0 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (22.1.0)
Requirement already satisfied: charset-normalizer<4.0,>=2.0 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (2.0.4)
Requirement already satisfied: multidict<7.0,>=4.5 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (6.0.2)
Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (4.0.2)
Requirement already satisfied: yarl<2.0,>=1.0 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (1.8.1)
Requirement already satisfied: frozenlist>=1.1.1 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (1.3.3)
Requirement already satisfied: aiosignal>=1.1.2 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (1.2.0)
Requirement already satisfied: soupsieve>1.2 in c:\programdata\anaconda3\lib\site-packages (from beautifulsoup4->dataframe_image) (2.4)
Requirement already satisfied: websocket-client<2.0.0,>=1.0.0 in c:\users\kemas\appdata\roaming\python\python311\site-packages (from html2image->dataframe_image) (1.8.0)
Requirement already satisfied: idna<4,>=2.5 in c:\programdata\anaconda3\lib\site-packages (from requests->dataframe_image) (3.4)
Requirement already satisfied: urllib3<3,>=1.21.1 in c:\programdata\anaconda3\lib\site-packages (from requests->dataframe_image) (1.26.16)
Requirement already satisfied: certifi>=2017.4.17 in c:\programdata\anaconda3\lib\site-packages (from requests->dataframe_image) (2023.11.17)
Requirement already satisfied: platformdirs>=2.5 in c:\programdata\anaconda3\lib\site-packages (from jupyter-core>=4.7->nbconvert>=5->dataframe_image) (3.10.0)
Requirement already satisfied: pywin32>=300 in c:\programdata\anaconda3\lib\site-packages (from jupyter-core>=4.7->nbconvert>=5->dataframe_image) (305.1)
Requirement already satisfied: jupyter-client>=6.1.5 in c:\programdata\anaconda3\lib\site-packages (from nbclient>=0.5.0->nbconvert>=5->dataframe_image) (7.4.9)
Requirement already satisfied: nest-asyncio in c:\programdata\anaconda3\lib\site-packages (from nbclient>=0.5.0->nbconvert>=5->dataframe_image) (1.5.6)
Requirement already satisfied: fastjsonschema in c:\programdata\anaconda3\lib\site-packages (from nbformat>=5.1->nbconvert>=5->dataframe_image) (2.16.2)
Requirement already satisfied: jsonschema>=2.6 in c:\programdata\anaconda3\lib\site-packages (from nbformat>=5.1->nbconvert>=5->dataframe_image) (4.17.3)
Requirement already satisfied: six>=1.5 in c:\programdata\anaconda3\lib\site-packages (from python-dateutil>=2.8.2->pandas>=0.24->dataframe_image) (1.16.0)
Requirement already satisfied: webencodings in c:\programdata\anaconda3\lib\site-packages (from bleach->nbconvert>=5->dataframe_image) (0.5.1)
Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in c:\programdata\anaconda3\lib\site-packages (from jsonschema>=2.6->nbformat>=5.1->nbconvert>=5->dataframe_image) (0.18.0)
Requirement already satisfied: pyzmq>=23.0 in c:\programdata\anaconda3\lib\site-packages (from jupyter-client>=6.1.5->nbclient>=0.5.0->nbconvert>=5->dataframe_image) (23.2.0)
Requirement already satisfied: tornado>=6.2 in c:\programdata\anaconda3\lib\site-packages (from jupyter-client>=6.1.5->nbclient>=0.5.0->nbconvert>=5->dataframe_image) (6.3.2)
DEPRECATION: Loading egg at c:\programdata\anaconda3\lib\site-packages\vboxapi-1.0-py3.11.egg is deprecated. pip 23.3 will enforce this behaviour change. A possible replacement is to use pip for package installation..
sales=pd.read_csv('C:/Users/KEMAS/myproject/dataset_2022.csv')
sales.shape
(2870, 10)
sales.head()
Property Type
District
Mukim
Scheme Name/Area
Month, Year of Transaction Date
Tenure
Land Area
Unit
Main Floor Area
Transaction Price
0
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Alor Gajah
TAMAN SERI BAYU
October 2022
Leasehold
143.0
sq.m
85.84
200000
1
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
July 2022
Freehold
143.0
sq.m
76.64
173000
2
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
September 2022
Freehold
143.0
sq.m
77.01
210000
3
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN BELIMBING HARMONI
October 2022
Leasehold
232.0
sq.m
75.72
361111
4
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN VISTA BELIMBING
January 2022
Freehold
128.0
sq.m
83.61
230000
sales.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2870 entries, 0 to 2869
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Property Type 2870 non-null object
1 District 2870 non-null object
2 Mukim 2870 non-null object
3 Scheme Name/Area 2870 non-null object
4 Month, Year of Transaction Date 2870 non-null object
5 Tenure 2870 non-null object
6 Land Area 2870 non-null float64
7 Unit 2870 non-null object
8 Main Floor Area 2870 non-null float64
9 Transaction Price 2870 non-null int64
dtypes: float64(2), int64(1), object(7)
memory usage: 224.3+ KB
print('Column name')
for col in sales.columns:
if sales[col].dtype=='object':
print(col, sales[col].nunique())
Column name
Property Type 2
District 3
Mukim 70
Scheme Name/Area 457
Month, Year of Transaction Date 12
Tenure 2
Unit 1
numer = ['Land Area','Main Floor Area','Transaction Price']
for col in numer:
sales[col] = pd.to_numeric(sales[col], errors='coerce')
categ = ['Property Type', 'District', 'Mukim', 'Scheme Name/Area', 'Tenure', 'Unit']
for col in categ:
sales[col] = sales[col].astype('category')
sales['Month, Year of Transaction Date'] = pd.to_datetime(sales['Month, Year of Transaction Date'], errors='coerce')
sales.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2870 entries, 0 to 2869
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Property Type 2870 non-null category
1 District 2870 non-null category
2 Mukim 2870 non-null category
3 Scheme Name/Area 2870 non-null category
4 Month, Year of Transaction Date 2870 non-null datetime64[ns]
5 Tenure 2870 non-null category
6 Land Area 2870 non-null float64
7 Unit 2870 non-null category
8 Main Floor Area 2870 non-null float64
9 Transaction Price 2870 non-null int64
dtypes: category(6), datetime64[ns](1), float64(2), int64(1)
memory usage: 132.3 KB
sales.isna().sum()
Property Type 0
District 0
Mukim 0
Scheme Name/Area 0
Month, Year of Transaction Date 0
Tenure 0
Land Area 0
Unit 0
Main Floor Area 0
Transaction Price 0
dtype: int64
sales
Property Type
District
Mukim
Scheme Name/Area
Month, Year of Transaction Date
Tenure
Land Area
Unit
Main Floor Area
Transaction Price
0
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Alor Gajah
TAMAN SERI BAYU
2022-10-01
Leasehold
143.0
sq.m
85.84
200000
1
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-07-01
Freehold
143.0
sq.m
76.64
173000
2
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-09-01
Freehold
143.0
sq.m
77.01
210000
3
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN BELIMBING HARMONI
2022-10-01
Leasehold
232.0
sq.m
75.72
361111
4
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN VISTA BELIMBING
2022-01-01
Freehold
128.0
sq.m
83.61
230000
...
...
...
...
...
...
...
...
...
...
...
2865
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-09-01
Freehold
205.0
sq.m
126.16
370000
2866
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-10-01
Freehold
111.0
sq.m
126.16
290000
2867
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN KASTURI FASA 1 & 2
2022-01-01
Freehold
143.0
sq.m
133.40
555000
2868
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN
2022-09-01
Freehold
200.0
sq.m
90.20
390000
2869
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN 8
2022-03-01
Freehold
168.0
sq.m
205.45
660000
sales['Land Size'] = sales['Land Area'] * 10.7639
sales['Build Size'] = sales['Main Floor Area'] * 10.7639
sales.drop(['Land Area', 'Main Floor Area'], axis=1, inplace=True)
sales
Property Type
District
Mukim
Scheme Name/Area
Month, Year of Transaction Date
Tenure
Unit
Transaction Price
Land Size
Build Size
0
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Alor Gajah
TAMAN SERI BAYU
2022-10-01
Leasehold
sq.m
200000
1539.2377
923.973176
1
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-07-01
Freehold
sq.m
173000
1539.2377
824.945296
2
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-09-01
Freehold
sq.m
210000
1539.2377
828.927939
3
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN BELIMBING HARMONI
2022-10-01
Leasehold
sq.m
361111
2497.2248
815.042508
4
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN VISTA BELIMBING
2022-01-01
Freehold
sq.m
230000
1377.7792
899.969679
...
...
...
...
...
...
...
...
...
...
...
2865
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-09-01
Freehold
sq.m
370000
2206.5995
1357.973624
2866
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-10-01
Freehold
sq.m
290000
1194.7929
1357.973624
2867
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN KASTURI FASA 1 & 2
2022-01-01
Freehold
sq.m
555000
1539.2377
1435.904260
2868
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN
2022-09-01
Freehold
sq.m
390000
2152.7800
970.903780
2869
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN 8
2022-03-01
Freehold
sq.m
660000
1808.3352
2211.443255
sales=sales[['Property Type','District','Mukim','Scheme Name/Area','Month, Year of Transaction Date', 'Tenure', 'Land Size', 'Unit', 'Build Size', 'Transaction Price']]
sales
Property Type
District
Mukim
Scheme Name/Area
Month, Year of Transaction Date
Tenure
Land Size
Unit
Build Size
Transaction Price
0
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Alor Gajah
TAMAN SERI BAYU
2022-10-01
Leasehold
1539.2377
sq.m
923.973176
200000
1
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-07-01
Freehold
1539.2377
sq.m
824.945296
173000
2
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-09-01
Freehold
1539.2377
sq.m
828.927939
210000
3
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN BELIMBING HARMONI
2022-10-01
Leasehold
2497.2248
sq.m
815.042508
361111
4
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN VISTA BELIMBING
2022-01-01
Freehold
1377.7792
sq.m
899.969679
230000
...
...
...
...
...
...
...
...
...
...
...
2865
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-09-01
Freehold
2206.5995
sq.m
1357.973624
370000
2866
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-10-01
Freehold
1194.7929
sq.m
1357.973624
290000
2867
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN KASTURI FASA 1 & 2
2022-01-01
Freehold
1539.2377
sq.m
1435.904260
555000
2868
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN
2022-09-01
Freehold
2152.7800
sq.m
970.903780
390000
2869
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN 8
2022-03-01
Freehold
1808.3352
sq.m
2211.443255
660000
sales['Unit'].replace('sq.m', 'sq.ft', inplace=True)
sales
Property Type
District
Mukim
Scheme Name/Area
Month, Year of Transaction Date
Tenure
Land Size
Unit
Build Size
Transaction Price
0
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Alor Gajah
TAMAN SERI BAYU
2022-10-01
Leasehold
1539.2377
sq.ft
923.973176
200000
1
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-07-01
Freehold
1539.2377
sq.ft
824.945296
173000
2
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-09-01
Freehold
1539.2377
sq.ft
828.927939
210000
3
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN BELIMBING HARMONI
2022-10-01
Leasehold
2497.2248
sq.ft
815.042508
361111
4
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN VISTA BELIMBING
2022-01-01
Freehold
1377.7792
sq.ft
899.969679
230000
...
...
...
...
...
...
...
...
...
...
...
2865
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-09-01
Freehold
2206.5995
sq.ft
1357.973624
370000
2866
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-10-01
Freehold
1194.7929
sq.ft
1357.973624
290000
2867
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN KASTURI FASA 1 & 2
2022-01-01
Freehold
1539.2377
sq.ft
1435.904260
555000
2868
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN
2022-09-01
Freehold
2152.7800
sq.ft
970.903780
390000
2869
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN 8
2022-03-01
Freehold
1808.3352
sq.ft
2211.443255
660000
latlong=pd.read_csv('C:/Users/KEMAS/myproject/latlong.csv')
latlong
Scheme Name/Area
Lat
Long
0
TAMAN SERI BAYU
2.384740
102.212509
1
TAMAN BKT INDAH
2.350550
102.103860
2
TAMAN BKT INDAH
2.350550
102.103860
3
TAMAN BELIMBING HARMONI
2.335506
102.266894
4
TAMAN VISTA BELIMBING
2.328142
102.266958
...
...
...
...
2865
TAMAN TG MINYAK UTAMA
2.268306
102.194419
2866
TAMAN TG MINYAK UTAMA
2.268306
102.194419
2867
TAMAN KASTURI FASA 1 & 2
2.192962
102.272744
2868
TAMAN SINN
2.194609
102.270545
2869
TAMAN SINN 8
2.191429
102.274285
latlong.drop(['Scheme Name/Area'], axis=1, inplace=True)
latlong
Lat
Long
0
2.384740
102.212509
1
2.350550
102.103860
2
2.350550
102.103860
3
2.335506
102.266894
4
2.328142
102.266958
...
...
...
2865
2.268306
102.194419
2866
2.268306
102.194419
2867
2.192962
102.272744
2868
2.194609
102.270545
2869
2.191429
102.274285
latlong.isna().sum()
Lat 0
Long 0
dtype: int64
new_sales = sales.merge(latlong, left_index=True, right_index=True)
new_sales
Property Type
District
Mukim
Scheme Name/Area
Month, Year of Transaction Date
Tenure
Land Size
Unit
Build Size
Transaction Price
Lat
Long
0
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Alor Gajah
TAMAN SERI BAYU
2022-10-01
Leasehold
1539.2377
sq.ft
923.973176
200000
2.384740
102.212509
1
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-07-01
Freehold
1539.2377
sq.ft
824.945296
173000
2.350550
102.103860
2
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2022-09-01
Freehold
1539.2377
sq.ft
828.927939
210000
2.350550
102.103860
3
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN BELIMBING HARMONI
2022-10-01
Leasehold
2497.2248
sq.ft
815.042508
361111
2.335506
102.266894
4
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN VISTA BELIMBING
2022-01-01
Freehold
1377.7792
sq.ft
899.969679
230000
2.328142
102.266958
...
...
...
...
...
...
...
...
...
...
...
...
...
2865
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-09-01
Freehold
2206.5995
sq.ft
1357.973624
370000
2.268306
102.194419
2866
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2022-10-01
Freehold
1194.7929
sq.ft
1357.973624
290000
2.268306
102.194419
2867
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN KASTURI FASA 1 & 2
2022-01-01
Freehold
1539.2377
sq.ft
1435.904260
555000
2.192962
102.272744
2868
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN
2022-09-01
Freehold
2152.7800
sq.ft
970.903780
390000
2.194609
102.270545
2869
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN 8
2022-03-01
Freehold
1808.3352
sq.ft
2211.443255
660000
2.191429
102.274285
new_sales=new_sales[['Property Type','District','Mukim','Scheme Name/Area', 'Lat', 'Long', 'Month, Year of Transaction Date', 'Tenure', 'Land Size', 'Unit', 'Build Size', 'Transaction Price']]
new_sales
Property Type
District
Mukim
Scheme Name/Area
Lat
Long
Month, Year of Transaction Date
Tenure
Land Size
Unit
Build Size
Transaction Price
0
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Alor Gajah
TAMAN SERI BAYU
2.384740
102.212509
2022-10-01
Leasehold
1539.2377
sq.ft
923.973176
200000
1
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2.350550
102.103860
2022-07-01
Freehold
1539.2377
sq.ft
824.945296
173000
2
1 - 1 1/2 Storey Terraced
Alor Gajah
Bdr Masjid Tanah
TAMAN BKT INDAH
2.350550
102.103860
2022-09-01
Freehold
1539.2377
sq.ft
828.927939
210000
3
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN BELIMBING HARMONI
2.335506
102.266894
2022-10-01
Leasehold
2497.2248
sq.ft
815.042508
361111
4
1 - 1 1/2 Storey Terraced
Alor Gajah
Belimbing
TAMAN VISTA BELIMBING
2.328142
102.266958
2022-01-01
Freehold
1377.7792
sq.ft
899.969679
230000
...
...
...
...
...
...
...
...
...
...
...
...
...
2865
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2.268306
102.194419
2022-09-01
Freehold
2206.5995
sq.ft
1357.973624
370000
2866
2 - 2 1/2 Storey Terraced
Melaka Tengah
Tg Minyak
TAMAN TG MINYAK UTAMA
2.268306
102.194419
2022-10-01
Freehold
1194.7929
sq.ft
1357.973624
290000
2867
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN KASTURI FASA 1 & 2
2.192962
102.272744
2022-01-01
Freehold
1539.2377
sq.ft
1435.904260
555000
2868
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN
2.194609
102.270545
2022-09-01
Freehold
2152.7800
sq.ft
970.903780
390000
2869
2 - 2 1/2 Storey Terraced
Melaka Tengah
Ujong Pasir
TAMAN SINN 8
2.191429
102.274285
2022-03-01
Freehold
1808.3352
sq.ft
2211.443255
660000
new_sales.to_csv('melaka_terraced_property_sales_2022.csv', index=False)
new_sales.to_csv('C:/Users/KEMAS/myproject/melaka_terraced_property_sales_2022.csv')
numerical_variables = new_sales.select_dtypes(include=['number']).columns
columns_to_exclude = ['Property Type','District','Mukim','Scheme Name/Area','Lat','Long','Month, Year of Transaction Date','Unit']
statistics = new_sales.drop(columns=columns_to_exclude).describe().round(2)
column_sums = new_sales[numerical_variables].sum()
statistics.loc['sum'] = column_sums
def format_accounting(value):
return "RM{:,.2f}".format(value)
formatted_statistics = statistics.style.format({
'Transaction Price': format_accounting
})
formatted_statistics = formatted_statistics.background_gradient()
dfi.export(formatted_statistics, 'formatted_statistics.png')
formatted_statistics
Land Size
Build Size
Transaction Price
count
2870.000000
2870.000000
RM2,870.00
mean
1643.010000
1149.640000
RM302,953.82
std
633.460000
447.150000
RM121,401.47
min
143.000000
520.000000
RM90,000.00
25%
1302.430000
819.990000
RM225,000.00
50%
1528.470000
989.960000
RM270,000.00
75%
1679.170000
1369.110000
RM363,675.00
max
8438.900000
4260.030000
RM1,200,000.00
sum
4715451.098807
3299474.606600
RM869,477,476.00
from matplotlib import pyplot as plt
import seaborn as sns
g = sns.FacetGrid(new_sales, col="Property Type", col_wrap=2, height=5, sharex=False, sharey=False)
g.map_dataframe(sns.boxplot, x='District', y='Transaction Price', hue='Tenure', palette='Blues')
g.add_legend(title='Tenure')
g.set_xticklabels(rotation=90)
g.set_axis_labels('District', 'Transaction Price in RM')
g.fig.subplots_adjust(top=0.9)
g.fig.suptitle('Boxplots for Transaction Price by District, Tenure and Property Type')
plt.show()
plt.savefig('Boxplot_for_Transaction_Price.png')
<Figure size 640x480 with 0 Axes>
from matplotlib import pyplot as plt
plt.subplots(figsize=(8, 8))
df_2dhist = pd.DataFrame({
x_label: grp['District'].value_counts()
for x_label, grp in new_sales.groupby('Property Type')
})
sns.heatmap(df_2dhist, cmap='Purples', annot=True, fmt='g')
plt.xlabel('Property Type')
plt.ylabel('District')
plt.title('Heatmap of Property Type vs District')
plt.show()
plt.savefig('Heatmap_District_Type.png')
<Figure size 640x480 with 0 Axes>
property_types_to_filter = ['1 - 1 1/2 Storey Terraced', '2 - 2 1/2 Storey Terraced']
new_district_counts_combined = new_sales[new_sales['Property Type'].isin(property_types_to_filter)] \
.groupby(['Property Type', 'District']) \
.size() \
.unstack(fill_value=0)
new_district_counts_combined['Total'] = new_district_counts_combined.sum(axis=1)
new_district_counts_combined.loc['Overall'] = new_district_counts_combined.sum(axis=0)
print(new_district_counts_combined)
dfi.export(new_district_counts_combined, 'type_counts.png')
District Alor Gajah Jasin Melaka Tengah Total
Property Type
1 - 1 1/2 Storey Terraced 375 471 969 1815
2 - 2 1/2 Storey Terraced 313 96 646 1055
Overall 688 567 1615 2870
plt.subplots(figsize=(8, 8))
df_2dhist = pd.DataFrame({
x_label: grp['Tenure'].value_counts()
for x_label, grp in new_sales.groupby('District')
})
sns.heatmap(df_2dhist, cmap='Blues', annot=True, fmt='g')
plt.xlabel('District')
plt.ylabel('Tenure')
plt.title('Heatmap of District vs Tenure')
plt.show()
plt.savefig('Heatmap_District_Tenure.png')
<Figure size 640x480 with 0 Axes>
tenure_to_filter = ['Freehold', 'Leasehold']
district_counts_combined = new_sales[new_sales['Tenure'].isin(tenure_to_filter)] \
.groupby(['District', 'Tenure']) \
.size() \
.unstack(fill_value=0)
district_counts_combined['Total'] = district_counts_combined.sum(axis=1)
district_counts_combined.loc['Overall'] = district_counts_combined.sum(axis=0)
print(district_counts_combined)
dfi.export(district_counts_combined, 'district_counts.png')
Tenure Freehold Leasehold Total
District
Alor Gajah 468 220 688
Jasin 311 256 567
Melaka Tengah 854 761 1615
Overall 1633 1237 2870
import plotly.express as px
fig = px.scatter_mapbox(new_sales, lat='Lat', lon='Long', color='Transaction Price', size='Transaction Price', hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True},
color_continuous_scale=px.colors.sequential.Viridis, mapbox_style='carto-positron', size_max=15, zoom=10)
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
new_sales['Transaction Count'] = new_sales.groupby('Scheme Name/Area')['Transaction Price'].transform('count')
fig = px.scatter_mapbox(new_sales, lat='Lat', lon='Long',
color='Transaction Count',
size='Transaction Count',
color_continuous_scale=px.colors.sequential.thermal,
hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True, 'Transaction Price': True},
size_max=15, zoom=10,
mapbox_style='carto-positron')
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
single_storey_filtered = new_sales[new_sales['Property Type'] == '1 - 1 1/2 Storey Terraced']
fig = px.scatter_mapbox(single_storey_filtered, lat='Lat', lon='Long', color='Transaction Price', size='Transaction Price', hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True},
color_continuous_scale=px.colors.sequential.Viridis, mapbox_style='carto-positron', size_max=15, zoom=10)
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
single_storey_filtered['Transaction Count'] = new_sales.groupby('Scheme Name/Area')['Transaction Price'].transform('count')
fig = px.scatter_mapbox(single_storey_filtered, lat='Lat', lon='Long',
color='Transaction Count',
size='Transaction Count',
color_continuous_scale=px.colors.sequential.thermal,
hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True, 'Transaction Price': True},
size_max=15, zoom=10,
mapbox_style='carto-positron')
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
double_storey_filtered = new_sales[new_sales['Property Type'] == '2 - 2 1/2 Storey Terraced']
fig = px.scatter_mapbox(single_storey_filtered, lat='Lat', lon='Long', color='Transaction Price', size='Transaction Price', hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True},
color_continuous_scale=px.colors.sequential.Viridis, mapbox_style='carto-positron', size_max=15, zoom=10)
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
double_storey_filtered['Transaction Count'] = new_sales.groupby('Scheme Name/Area')['Transaction Price'].transform('count')
fig = px.scatter_mapbox(double_storey_filtered, lat='Lat', lon='Long',
color='Transaction Count',
size='Transaction Count',
color_continuous_scale=px.colors.sequential.thermal,
hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True, 'Transaction Price': True},
size_max=15, zoom=10,
mapbox_style='carto-positron')
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
plt.title('Transaction Price Distribution Plot')
sns.distplot(new_sales['Transaction Price'])
plt.show()
plt.title('Build Size Distribution Plot')
sns.distplot(new_sales['Build Size'])
plt.show()
from sklearn.linear_model import LinearRegression
X = new_sales[['Build Size', 'Land Size']]
y = new_sales['Transaction Price']
model = LinearRegression()
model.fit(X, y)
print('Coefficients:', model.coef_)
print('Intercept:', model.intercept_)
Coefficients: [195.02512463 55.36908406]
Intercept: -12227.588369571953
Price = -12227.588369571662 + 55.36908406 * 1643.01 + 195.02512463 * 1149.64
Price
302953.05471148214