데이터 분석가:Applied Data Analytics/판다스 데이터분석

4. Data transformation - 영국시장의 중고 자동차 가격 데이터 다루기[프로젝트]

데이터분석 2025. 2. 13. 17:07
320x100
728x90

해당 프로젝트는 "모두연 PDA(프로덕트데이터분석)1기 수업과정" 에서 수행한 내용을 기준으로 작성했습니다.

 

import pandas as pd
import numpy as np
import seaborn as sns
In [3]:
car_df = pd.read_csv('../../data/cars.csv')
In [5]:
brand_df = pd.read_csv('../../data/brand.csv')
In [6]:
car_df.head()
Out[6]:
 
brand_df.head()
Out[7]:
In [8]:
car_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3687 entries, 0 to 3686
Data columns (total 13 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   title              3687 non-null   object 
 1   Price              3687 non-null   int64  
 2   Mileage(miles)     3687 non-null   int64  
 3   Registration_Year  3687 non-null   int64  
 4   Previous Owners    2276 non-null   float64
 5   Fuel type          3687 non-null   object 
 6   Body type          3687 non-null   object 
 7   Engine             3642 non-null   object 
 8   Gearbox            3687 non-null   object 
 9   Doors              3662 non-null   float64
 10  Seats              3652 non-null   float64
 11  Emission Class     3600 non-null   object 
 12  Service history    540 non-null    object 
dtypes: float64(3), int64(3), object(7)
memory usage: 374.6+ KB
In [9]:
brand_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 48 entries, 0 to 47
Data columns (total 2 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   title    48 non-null     object
 1   country  48 non-null     object
dtypes: object(2)
memory usage: 896.0+ bytes
In [10]:
car_df["Brand"] = car_df["title"].str.split().str[0]
In [11]:
merged_left = car_df.merge(brand_df, left_on="Brand", right_on="title", how="left").drop(columns=["title_y"])
merged_left.rename(columns={"title_x": "title"}, inplace=True)
In [12]:
print(merged_left)   # 1. cars.csv와 brand.csv의 데이터 합치기
               title  Price  Mileage(miles)  Registration_Year  \
0        SKODA FABIA   6900           70189               2016   
1     VAUXHALL CORSA   1495           88585               2008   
2        HYUNDAI I30    949          137000               2011   
3         MINI HATCH   2395           96731               2010   
4     VAUXHALL CORSA   1000           85000               2013   
...              ...    ...             ...                ...   
3682  RENAULT MEGANE   1395           76202               2006   
3683         AUDI A4   6990          119000               2012   
3684    BMW 3 SERIES   3995          139000               2013   
3685    HONDA ACCORD   1390          179190               2007   
3686  VAUXHALL CORSA   2000           82160               2013   

      Previous Owners Fuel type  Body type Engine Gearbox  Doors  Seats  \
0                 3.0    Diesel  Hatchback   1.4L  Manual    5.0    5.0   
1                 4.0    Petrol  Hatchback   1.2L  Manual    3.0    5.0   
2                 NaN    Petrol  Hatchback   1.4L  Manual    5.0    5.0   
3                 5.0    Petrol  Hatchback   1.4L  Manual    3.0    4.0   
4                 NaN    Diesel  Hatchback   1.3L  Manual    5.0    5.0   
...               ...       ...        ...    ...     ...    ...    ...   
3682              4.0    Petrol  Hatchback   1.6L  Manual    5.0    5.0   
3683              NaN    Petrol     Saloon   2.0L  Manual    4.0    5.0   
3684              NaN    Diesel     Saloon   2.0L  Manual    4.0    5.0   
3685              NaN    Diesel     Estate   2.2L  Manual    5.0    5.0   
3686              7.0    Petrol  Hatchback   1.2L  Manual    5.0    5.0   

     Emission Class Service history     Brand country  
0            Euro 6             NaN     SKODA     NaN  
1            Euro 4            Full  VAUXHALL     NaN  
2            Euro 5             NaN   HYUNDAI     NaN  
3            Euro 4            Full      MINI     NaN  
4            Euro 5             NaN  VAUXHALL     NaN  
...             ...             ...       ...     ...  
3682         Euro 4             NaN   RENAULT     NaN  
3683         Euro 5             NaN      AUDI     NaN  
3684         Euro 5             NaN       BMW     NaN  
3685         Euro 4            Full     HONDA     NaN  
3686         Euro 5             NaN  VAUXHALL     NaN  

[3687 rows x 15 columns]
In [14]:
merged_inner = car_df.merge(brand_df, left_on="Brand", right_on="title", how="inner").drop(columns=["title_y"])
merged_inner.rename(columns={"title_x": "title"}, inplace=True)
In [15]:
print(merged_inner)
Empty DataFrame
Columns: [title, Price, Mileage(miles), Registration_Year, Previous Owners, Fuel type, Body type, Engine, Gearbox, Doors, Seats, Emission Class, Service history, Brand, country]
Index: []
In [16]:
merged_outer = car_df.merge(brand_df, left_on="Brand", right_on="title", how="outer").drop(columns=["title_y"])
merged_outer.rename(columns={"title_x": "title"}, inplace=True)
In [17]:
print(merged_outer)
            title   Price  Mileage(miles)  Registration_Year  Previous Owners  \
0     SKODA FABIA  6900.0         70189.0             2016.0              3.0   
1     SKODA FABIA  6900.0         70189.0             2016.0              3.0   
2     SKODA FABIA  1990.0        150000.0             2007.0              2.0   
3     SKODA FABIA  1995.0         84000.0             2008.0              NaN   
4     SKODA FABIA  2495.0        124138.0             2011.0              3.0   
...           ...     ...             ...                ...              ...   
3730          NaN     NaN             NaN                NaN              NaN   
3731          NaN     NaN             NaN                NaN              NaN   
3732          NaN     NaN             NaN                NaN              NaN   
3733          NaN     NaN             NaN                NaN              NaN   
3734          NaN     NaN             NaN                NaN              NaN   

     Fuel type  Body type Engine    Gearbox  Doors  Seats Emission Class  \
0       Diesel  Hatchback   1.4L     Manual    5.0    5.0         Euro 6   
1       Diesel  Hatchback   1.4L     Manual    5.0    5.0         Euro 6   
2       Diesel  Hatchback   1.9L     Manual    5.0    5.0         Euro 4   
3       Petrol  Hatchback   1.4L     Manual    5.0    5.0         Euro 4   
4       Petrol  Hatchback   1.2L  Automatic    5.0    5.0         Euro 5   
...        ...        ...    ...        ...    ...    ...            ...   
3730       NaN        NaN    NaN        NaN    NaN    NaN            NaN   
3731       NaN        NaN    NaN        NaN    NaN    NaN            NaN   
3732       NaN        NaN    NaN        NaN    NaN    NaN            NaN   
3733       NaN        NaN    NaN        NaN    NaN    NaN            NaN   
3734       NaN        NaN    NaN        NaN    NaN    NaN            NaN   

     Service history  Brand         country  
0                NaN  SKODA             NaN  
1                NaN  SKODA             NaN  
2               Full  SKODA             NaN  
3                NaN  SKODA             NaN  
4                NaN  SKODA             NaN  
...              ...    ...             ...  
3730             NaN    NaN  United Kingdom  
3731             NaN    NaN           Italy  
3732             NaN    NaN     South Korea  
3733             NaN    NaN  United Kingdom  
3734             NaN    NaN           Japan  

[3735 rows x 15 columns]
In [18]:
merged_right = car_df.merge(brand_df, left_on="Brand", right_on="title", how="right").drop(columns=["title_y"])
merged_right.rename(columns={"title_x": "title"}, inplace=True)
In [19]:
print(merged_right)
   title  Price  Mileage(miles)  Registration_Year  Previous Owners Fuel type  \
0    NaN    NaN             NaN                NaN              NaN       NaN   
1    NaN    NaN             NaN                NaN              NaN       NaN   
2    NaN    NaN             NaN                NaN              NaN       NaN   
3    NaN    NaN             NaN                NaN              NaN       NaN   
4    NaN    NaN             NaN                NaN              NaN       NaN   
5    NaN    NaN             NaN                NaN              NaN       NaN   
6    NaN    NaN             NaN                NaN              NaN       NaN   
7    NaN    NaN             NaN                NaN              NaN       NaN   
8    NaN    NaN             NaN                NaN              NaN       NaN   
9    NaN    NaN             NaN                NaN              NaN       NaN   
10   NaN    NaN             NaN                NaN              NaN       NaN   
11   NaN    NaN             NaN                NaN              NaN       NaN   
12   NaN    NaN             NaN                NaN              NaN       NaN   
13   NaN    NaN             NaN                NaN              NaN       NaN   
14   NaN    NaN             NaN                NaN              NaN       NaN   
15   NaN    NaN             NaN                NaN              NaN       NaN   
16   NaN    NaN             NaN                NaN              NaN       NaN   
17   NaN    NaN             NaN                NaN              NaN       NaN   
18   NaN    NaN             NaN                NaN              NaN       NaN   
19   NaN    NaN             NaN                NaN              NaN       NaN   
20   NaN    NaN             NaN                NaN              NaN       NaN   
21   NaN    NaN             NaN                NaN              NaN       NaN   
22   NaN    NaN             NaN                NaN              NaN       NaN   
23   NaN    NaN             NaN                NaN              NaN       NaN   
24   NaN    NaN             NaN                NaN              NaN       NaN   
25   NaN    NaN             NaN                NaN              NaN       NaN   
26   NaN    NaN             NaN                NaN              NaN       NaN   
27   NaN    NaN             NaN                NaN              NaN       NaN   
28   NaN    NaN             NaN                NaN              NaN       NaN   
29   NaN    NaN             NaN                NaN              NaN       NaN   
30   NaN    NaN             NaN                NaN              NaN       NaN   
31   NaN    NaN             NaN                NaN              NaN       NaN   
32   NaN    NaN             NaN                NaN              NaN       NaN   
33   NaN    NaN             NaN                NaN              NaN       NaN   
34   NaN    NaN             NaN                NaN              NaN       NaN   
35   NaN    NaN             NaN                NaN              NaN       NaN   
36   NaN    NaN             NaN                NaN              NaN       NaN   
37   NaN    NaN             NaN                NaN              NaN       NaN   
38   NaN    NaN             NaN                NaN              NaN       NaN   
39   NaN    NaN             NaN                NaN              NaN       NaN   
40   NaN    NaN             NaN                NaN              NaN       NaN   
41   NaN    NaN             NaN                NaN              NaN       NaN   
42   NaN    NaN             NaN                NaN              NaN       NaN   
43   NaN    NaN             NaN                NaN              NaN       NaN   
44   NaN    NaN             NaN                NaN              NaN       NaN   
45   NaN    NaN             NaN                NaN              NaN       NaN   
46   NaN    NaN             NaN                NaN              NaN       NaN   
47   NaN    NaN             NaN                NaN              NaN       NaN   

   Body type Engine Gearbox  Doors  Seats Emission Class Service history  \
0        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
1        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
2        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
3        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
4        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
5        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
6        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
7        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
8        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
9        NaN    NaN     NaN    NaN    NaN            NaN             NaN   
10       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
11       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
12       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
13       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
14       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
15       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
16       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
17       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
18       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
19       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
20       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
21       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
22       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
23       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
24       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
25       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
26       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
27       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
28       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
29       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
30       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
31       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
32       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
33       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
34       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
35       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
36       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
37       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
38       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
39       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
40       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
41       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
42       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
43       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
44       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
45       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
46       NaN    NaN     NaN    NaN    NaN            NaN             NaN   
47       NaN    NaN     NaN    NaN    NaN            NaN             NaN   

   Brand         country  
0    NaN  Czech Republic  
1    NaN  United Kingdom  
2    NaN     South Korea  
3    NaN  United Kingdom  
4    NaN   United States  
5    NaN          Sweden  
6    NaN          France  
7    NaN         Germany  
8    NaN          France  
9    NaN         Germany  
10   NaN           Japan  
11   NaN          Sweden  
12   NaN         Germany  
13   NaN           Japan  
14   NaN  United Kingdom  
15   NaN           Japan  
16   NaN           Spain  
17   NaN           Japan  
18   NaN           Italy  
19   NaN          France  
20   NaN     South Korea  
21   NaN        Malaysia  
22   NaN           Italy  
23   NaN         Germany  
24   NaN           Japan  
25   NaN           Japan  
26   NaN  United Kingdom  
27   NaN   United States  
28   NaN           Japan  
29   NaN         Romania  
30   NaN           Japan  
31   NaN   United States  
32   NaN  United Kingdom  
33   NaN   United States  
34   NaN  United Kingdom  
35   NaN          France  
36   NaN     South Korea  
37   NaN   United States  
38   NaN         Germany  
39   NaN           Japan  
40   NaN           Japan  
41   NaN           Italy  
42   NaN         Germany  
43   NaN  United Kingdom  
44   NaN           Italy  
45   NaN     South Korea  
46   NaN  United Kingdom  
47   NaN           Japan  
In [20]:
print("Left Join:", merged_left.shape)
Left Join: (3687, 15)
In [21]:

 

print("Inner Join:", merged_inner.shape)
Inner Join: (0, 15)
In [22]:
print("Outer Join:", merged_outer.shape)
print("Right Join:", merged_right.shape)
Outer Join: (3735, 15)
Right Join: (48, 15)
In [23]:
print(merged_left)
               title  Price  Mileage(miles)  Registration_Year  \
0        SKODA FABIA   6900           70189               2016   
1     VAUXHALL CORSA   1495           88585               2008   
2        HYUNDAI I30    949          137000               2011   
3         MINI HATCH   2395           96731               2010   
4     VAUXHALL CORSA   1000           85000               2013   
...              ...    ...             ...                ...   
3682  RENAULT MEGANE   1395           76202               2006   
3683         AUDI A4   6990          119000               2012   
3684    BMW 3 SERIES   3995          139000               2013   
3685    HONDA ACCORD   1390          179190               2007   
3686  VAUXHALL CORSA   2000           82160               2013   

      Previous Owners Fuel type  Body type Engine Gearbox  Doors  Seats  \
0                 3.0    Diesel  Hatchback   1.4L  Manual    5.0    5.0   
1                 4.0    Petrol  Hatchback   1.2L  Manual    3.0    5.0   
2                 NaN    Petrol  Hatchback   1.4L  Manual    5.0    5.0   
3                 5.0    Petrol  Hatchback   1.4L  Manual    3.0    4.0   
4                 NaN    Diesel  Hatchback   1.3L  Manual    5.0    5.0   
...               ...       ...        ...    ...     ...    ...    ...   
3682              4.0    Petrol  Hatchback   1.6L  Manual    5.0    5.0   
3683              NaN    Petrol     Saloon   2.0L  Manual    4.0    5.0   
3684              NaN    Diesel     Saloon   2.0L  Manual    4.0    5.0   
3685              NaN    Diesel     Estate   2.2L  Manual    5.0    5.0   
3686              7.0    Petrol  Hatchback   1.2L  Manual    5.0    5.0   

     Emission Class Service history     Brand country  
0            Euro 6             NaN     SKODA     NaN  
1            Euro 4            Full  VAUXHALL     NaN  
2            Euro 5             NaN   HYUNDAI     NaN  
3            Euro 4            Full      MINI     NaN  
4            Euro 5             NaN  VAUXHALL     NaN  
...             ...             ...       ...     ...  
3682         Euro 4             NaN   RENAULT     NaN  
3683         Euro 5             NaN      AUDI     NaN  
3684         Euro 5             NaN       BMW     NaN  
3685         Euro 4            Full     HONDA     NaN  
3686         Euro 5             NaN  VAUXHALL     NaN  

[3687 rows x 15 columns]
In [24]:
car_df["Brand"] = car_df["title"].str.split().str[0].str.upper()
In [25]:
print(car_df[["title", "Brand"]].head(10))
            title     Brand
0     SKODA FABIA     SKODA
1  VAUXHALL CORSA  VAUXHALL
2     HYUNDAI I30   HYUNDAI
3      MINI HATCH      MINI
4  VAUXHALL CORSA  VAUXHALL
5   HYUNDAI COUPE   HYUNDAI
6      FORD FOCUS      FORD
7  VAUXHALL CORSA  VAUXHALL
8       VOLVO 740     VOLVO
9     PEUGEOT 207   PEUGEOT
In [26]:
unique_engines = car_df["Engine"].unique()
In [27]:
print(unique_engines)
['1.4L' '1.2L' '1.3L' '2.0L' '1.6L' '2.3L' '1.8L' '1.0L' '3.0L' '1.5L'
 '1.9L' '2.4L' '2.2L' '3.5L' '3.2L' '2.5L' '1.1L' '3.1L' '3.7L' '2.6L'
 '2.1L' '2.8L' '5.0L' '0.8L' '2.7L' '1.7L' '0.9L' '4.2L' nan '4.4L' '4.3L'
 '3.3L' '5.5L' '4.8L' '6.3L']
In [28]:
unique_emission_classes = car_df["Emission Class"].unique()
print(unique_emission_classes)
['Euro 6' 'Euro 4' 'Euro 5' nan 'Euro 3' 'Euro 2' 'Euro 1']
In [29]:
from sklearn.preprocessing import LabelEncoder    
# LabelEncoder
le_engine = LabelEncoder()
le_emission = LabelEncoder()
# Engine과 Emission Class 변수를 숫자로 변환     #2. 카테고리형 변수를 숫자 형태로 변환하기
car_df["Engine_Encoded"] = le_engine.fit_transform(car_df["Engine"].astype(str))Emission_Class_Encoded
car_df["Emission_Class_Encoded"] = le_emission.fit_transform(car_df["Emission Class"].astype(str))
In [30]:
print(car_df[["Engine", "Engine_Encoded", "Emission Class", "Emission_Class_Encoded"]].head(10))
  Engine  Engine_Encoded Emission Class  Emission_Class_Encoded
0   1.4L               6         Euro 6                       5
1   1.2L               4         Euro 4                       3
2   1.4L               6         Euro 5                       4
3   1.4L               6         Euro 4                       3
4   1.3L               5         Euro 5                       4
5   2.0L              12         Euro 4                       3
6   1.6L               8         Euro 4                       3
7   1.2L               4         Euro 4                       3
8   2.3L              15            NaN                       6
9   1.6L               8         Euro 4                       3
In [31]:
print(car_df[["Engine", "Engine_Encoded", "Emission Class", "Emission_Class_Encoded"]].tail(10))
     Engine  Engine_Encoded Emission Class  Emission_Class_Encoded
3677   2.7L              19            NaN                       6
3678   3.7L              26         Euro 3                       2
3679   2.2L              14         Euro 2                       1
3680   1.4L               6         Euro 4                       3
3681   1.6L               8         Euro 4                       3
3682   1.6L               8         Euro 4                       3
3683   2.0L              12         Euro 5                       4
3684   2.0L              12         Euro 5                       4
3685   2.2L              14         Euro 4                       3
3686   1.2L               4         Euro 5                       4
In [32]:
new_car_df = car_df.dropna(subset=["Engine", "Emission Class"])  #NaN있는 행을 삭제후 new_car_df에저장
print(new_car_df.info())
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3599 entries, 0 to 3686
Data columns (total 16 columns):
 #   Column                  Non-Null Count  Dtype  
---  ------                  --------------  -----  
 0   title                   3599 non-null   object 
 1   Price                   3599 non-null   int64  
 2   Mileage(miles)          3599 non-null   int64  
 3   Registration_Year       3599 non-null   int64  
 4   Previous Owners         2243 non-null   float64
 5   Fuel type               3599 non-null   object 
 6   Body type               3599 non-null   object 
 7   Engine                  3599 non-null   object 
 8   Gearbox                 3599 non-null   object 
 9   Doors                   3599 non-null   float64
 10  Seats                   3593 non-null   float64
 11  Emission Class          3599 non-null   object 
 12  Service history         534 non-null    object 
 13  Brand                   3599 non-null   object 
 14  Engine_Encoded          3599 non-null   int64  
 15  Emission_Class_Encoded  3599 non-null   int64  
dtypes: float64(3), int64(5), object(8)
memory usage: 478.0+ KB
None
In [33]:
print(new_car_df[["Engine", "Engine_Encoded", "Emission Class", "Emission_Class_Encoded"]].tail(10))
     Engine  Engine_Encoded Emission Class  Emission_Class_Encoded
3676   1.6L               8         Euro 6                       5
3678   3.7L              26         Euro 3                       2
3679   2.2L              14         Euro 2                       1
3680   1.4L               6         Euro 4                       3
3681   1.6L               8         Euro 4                       3
3682   1.6L               8         Euro 4                       3
3683   2.0L              12         Euro 5                       4
3684   2.0L              12         Euro 5                       4
3685   2.2L              14         Euro 4                       3
3686   1.2L               4         Euro 5                       4
In [34]:
print(new_car_df[["Engine", "Engine_Encoded", "Emission Class", "Emission_Class_Encoded"]].head(10))
   Engine  Engine_Encoded Emission Class  Emission_Class_Encoded
0    1.4L               6         Euro 6                       5
1    1.2L               4         Euro 4                       3
2    1.4L               6         Euro 5                       4
3    1.4L               6         Euro 4                       3
4    1.3L               5         Euro 5                       4
5    2.0L              12         Euro 4                       3
6    1.6L               8         Euro 4                       3
7    1.2L               4         Euro 4                       3
9    1.6L               8         Euro 4                       3
10   1.6L               8         Euro 4                       3
In [35]:
print(car_df.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3687 entries, 0 to 3686
Data columns (total 16 columns):
 #   Column                  Non-Null Count  Dtype  
---  ------                  --------------  -----  
 0   title                   3687 non-null   object 
 1   Price                   3687 non-null   int64  
 2   Mileage(miles)          3687 non-null   int64  
 3   Registration_Year       3687 non-null   int64  
 4   Previous Owners         2276 non-null   float64
 5   Fuel type               3687 non-null   object 
 6   Body type               3687 non-null   object 
 7   Engine                  3642 non-null   object 
 8   Gearbox                 3687 non-null   object 
 9   Doors                   3662 non-null   float64
 10  Seats                   3652 non-null   float64
 11  Emission Class          3600 non-null   object 
 12  Service history         540 non-null    object 
 13  Brand                   3687 non-null   object 
 14  Engine_Encoded          3687 non-null   int64  
 15  Emission_Class_Encoded  3687 non-null   int64  
dtypes: float64(3), int64(5), object(8)
memory usage: 461.0+ KB
None
In [36]:
car_df["Engine_Encoded"] = car_df["Engine"].str.replace("L", "", regex=True).astype(float)
In [37]:
car_df["Emission_Class_Encoded"] = car_df["Emission Class"].str.replace("Euro ", "", regex=True).astype(float)
In [38]:
print(car_df[["Engine", "Engine_Encoded", "Emission Class", "Emission_Class_Encoded"]].head(10))
  Engine  Engine_Encoded Emission Class  Emission_Class_Encoded
0   1.4L             1.4         Euro 6                     6.0
1   1.2L             1.2         Euro 4                     4.0
2   1.4L             1.4         Euro 5                     5.0
3   1.4L             1.4         Euro 4                     4.0
4   1.3L             1.3         Euro 5                     5.0
5   2.0L             2.0         Euro 4                     4.0
6   1.6L             1.6         Euro 4                     4.0
7   1.2L             1.2         Euro 4                     4.0
8   2.3L             2.3            NaN                     NaN
9   1.6L             1.6         Euro 4                     4.0
In [39]:
print(car_df[["Engine", "Engine_Encoded", "Emission Class", "Emission_Class_Encoded"]].tail(10))
     Engine  Engine_Encoded Emission Class  Emission_Class_Encoded
3677   2.7L             2.7            NaN                     NaN
3678   3.7L             3.7         Euro 3                     3.0
3679   2.2L             2.2         Euro 2                     2.0
3680   1.4L             1.4         Euro 4                     4.0
3681   1.6L             1.6         Euro 4                     4.0
3682   1.6L             1.6         Euro 4                     4.0
3683   2.0L             2.0         Euro 5                     5.0
3684   2.0L             2.0         Euro 5                     5.0
3685   2.2L             2.2         Euro 4                     4.0
3686   1.2L             1.2         Euro 5                     5.0
In [40]:
renew_car_df = car_df.dropna(subset=["Engine_Encoded", "Emission_Class_Encoded"])    #null값의 행 삭제 하여 renew_car_df에 저장
In [41]:
print(renew_car_df.info())
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3599 entries, 0 to 3686
Data columns (total 16 columns):
 #   Column                  Non-Null Count  Dtype  
---  ------                  --------------  -----  
 0   title                   3599 non-null   object 
 1   Price                   3599 non-null   int64  
 2   Mileage(miles)          3599 non-null   int64  
 3   Registration_Year       3599 non-null   int64  
 4   Previous Owners         2243 non-null   float64
 5   Fuel type               3599 non-null   object 
 6   Body type               3599 non-null   object 
 7   Engine                  3599 non-null   object 
 8   Gearbox                 3599 non-null   object 
 9   Doors                   3599 non-null   float64
 10  Seats                   3593 non-null   float64
 11  Emission Class          3599 non-null   object 
 12  Service history         534 non-null    object 
 13  Brand                   3599 non-null   object 
 14  Engine_Encoded          3599 non-null   float64
 15  Emission_Class_Encoded  3599 non-null   float64
dtypes: float64(5), int64(3), object(8)
memory usage: 478.0+ KB
None
In [42]:
import matplotlib.pyplot as plt
import seaborn as sns
In [43]:
renew_car_df.describe()
Out[43]:
In [44]:
#결측치 개수 및 비율
missing_count = renew_car_df.isnull().sum()
# 결측치 비율 
missing_ratio = (renew_car_df.isnull().sum() / len(car_df)) * 100
# 결측치 개수 및 비율을 데이터프레임에
missing_data = pd.DataFrame({"Missing Count": missing_count, "Missing Ratio (%)": missing_ratio})
# 결측치 개수 및 비율 출력
print(missing_data)
                        Missing Count  Missing Ratio (%)
title                               0           0.000000
Price                               0           0.000000
Mileage(miles)                      0           0.000000
Registration_Year                   0           0.000000
Previous Owners                  1356          36.777868
Fuel type                           0           0.000000
Body type                           0           0.000000
Engine                              0           0.000000
Gearbox                             0           0.000000
Doors                               0           0.000000
Seats                               6           0.162734
Emission Class                      0           0.000000
Service history                  3065          83.129916
Brand                               0           0.000000
Engine_Encoded                      0           0.000000
Emission_Class_Encoded              0           0.000000
In [47]:
# Service history 변수의 결측치는 'Unknown'으로 채우고, 결측치 변수가 일정 개수 이상 포함된 데이터는 제거
renew_car_df = renew_car_df.copy()
renew_car_df["Service history"].fillna("Unknown", inplace=True)
threshold = 2  # 허용할 수 있는 최대 결측치 개수 2
renew_car_df = renew_car_df.dropna(thresh=renew_car_df.shape[1] - threshold)
In [48]:
print(renew_car_df.info())
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3599 entries, 0 to 3686
Data columns (total 16 columns):
 #   Column                  Non-Null Count  Dtype  
---  ------                  --------------  -----  
 0   title                   3599 non-null   object 
 1   Price                   3599 non-null   int64  
 2   Mileage(miles)          3599 non-null   int64  
 3   Registration_Year       3599 non-null   int64  
 4   Previous Owners         2243 non-null   float64
 5   Fuel type               3599 non-null   object 
 6   Body type               3599 non-null   object 
 7   Engine                  3599 non-null   object 
 8   Gearbox                 3599 non-null   object 
 9   Doors                   3599 non-null   float64
 10  Seats                   3593 non-null   float64
 11  Emission Class          3599 non-null   object 
 12  Service history         3599 non-null   object 
 13  Brand                   3599 non-null   object 
 14  Engine_Encoded          3599 non-null   float64
 15  Emission_Class_Encoded  3599 non-null   float64
dtypes: float64(5), int64(3), object(8)
memory usage: 478.0+ KB
None
In [49]:
from sklearn.preprocessing import StandardScaler
# StandardScaler
scaler_standard = StandardScaler()
scaled_standard = scaler_standard.fit_transform(renew_car_df.select_dtypes(include=[np.number]))
# 데이터프레임 저장
renew_car_df_standard = pd.DataFrame(scaled_standard, columns=renew_car_df.select_dtypes(include=[np.number]).columns)
print(renew_car_df_standard.head())
      Price  Mileage(miles)  Registration_Year  Previous Owners     Doors  \
0  0.246192       -0.286646           0.851866         0.124533  0.691568   
1 -0.951803        0.178401          -0.822670         0.772625 -1.332794   
2 -1.072821        1.402323          -0.194719              NaN  0.691568   
3 -0.752322        0.384331          -0.404036         1.420717 -1.332794   
4 -1.061517        0.087773           0.223915              NaN  0.691568   

      Seats  Engine_Encoded  Emission_Class_Encoded  
0  0.176100       -0.419659                1.196926  
1  0.176100       -0.831535               -0.999218  
2  0.176100       -0.419659                0.098854  
3 -1.562161       -0.419659               -0.999218  
4  0.176100       -0.625597                0.098854  
In [50]:
renew_car_df_standard.describe()
Out[50]:
In [51]:
from sklearn.preprocessing import MinMaxScaler
# MinMaxScaler
scaler_minmax = MinMaxScaler()
scaled_minmax = scaler_minmax.fit_transform(renew_car_df.select_dtypes(include=[np.number]))
# 데이터프레임 저장
renew_car_df_minmax = pd.DataFrame(scaled_minmax, columns=renew_car_df.select_dtypes(include=[np.number]).columns)
print(renew_car_df_minmax.head())
      Price  Mileage(miles)  Registration_Year  Previous Owners     Doors  \
0  0.194030        0.063227           0.774194            0.250  1.000000   
1  0.032687        0.079798           0.516129            0.375  0.333333   
2  0.016388        0.123412           0.612903              NaN  1.000000   
3  0.059552        0.087136           0.580645            0.500  0.333333   
4  0.017910        0.076569           0.677419              NaN  1.000000   

   Seats  Engine_Encoded  Emission_Class_Encoded  
0    0.6        0.109091                     1.0  
1    0.6        0.072727                     0.6  
2    0.6        0.109091                     0.8  
3    0.4        0.109091                     0.6  
4    0.6        0.090909                     0.8  
In [52]:
renew_car_df_minmax.describe()
Out[52]:
In [53]:
from sklearn.preprocessing import MaxAbsScaler
# MaxAbsScaler 
scaler_maxabs = MaxAbsScaler()
scaled_maxabs = scaler_maxabs.fit_transform(renew_car_df.select_dtypes(include=[np.number]))
# 데이터프레임 저장
renew_car_df_maxabs = pd.DataFrame(scaled_maxabs, columns=renew_car_df.select_dtypes(include=[np.number]).columns)
print(renew_car_df_maxabs.head())
      Price  Mileage(miles)  Registration_Year  Previous Owners  Doors  \
0  0.203540        0.063228           0.996540         0.333333    1.0   
1  0.044100        0.079799           0.992585         0.444444    0.6   
2  0.027994        0.123412           0.994068              NaN    1.0   
3  0.070649        0.087137           0.993574         0.555556    0.6   
4  0.029499        0.076570           0.995057              NaN    1.0   

      Seats  Engine_Encoded  Emission_Class_Encoded  
0  0.714286        0.222222                1.000000  
1  0.714286        0.190476                0.666667  
2  0.714286        0.222222                0.833333  
3  0.571429        0.222222                0.666667  
4  0.714286        0.206349                0.833333  
In [54]:
renew_car_df_maxabs.describe()
Out[54]:
In [55]:
sns.scatterplot(x=renew_car_df_standard["Mileage(miles)"], y=renew_car_df_standard["Price"]) #주행거리 vs 가격
plt.title("Mileage vs Price (StandardScaler)")
plt.show()                                            # 주행거리가 많을수록 가격 하락
In [56]:
sns.scatterplot(x=renew_car_df_standard["Registration_Year"], y=renew_car_df_standard["Price"]) #등록연도 vs 가격
plt.title("Registration Year vs Price (StandardScaler)")
plt.show()                                                      #등록연도가 최근일수 록 가격 상승
In [57]:
sns.scatterplot(x=renew_car_df_standard["Engine_Encoded"], y=renew_car_df_standard["Price"]) #배기랑 vs 가격
plt.title("Engine Size vs Price (StandardScaler)")                          
plt.show()                                                           # 가격0이하 삭제이후 재검토
In [60]:
sns.scatterplot(x=renew_car_df_standard["Emission_Class_Encoded"], y=renew_car_df_standard["Price"]) #배출등급 vs 가격
plt.title("Emission Class vs Price (StandardScaler)")
plt.show()                                                     #배출 등급이 좋을수록 가격 상승
In [61]:
sns.scatterplot(x=renew_car_df_standard["Seats"], y=renew_car_df_standard["Price"]) #좌석수 vs 가격
plt.title("Seats vs Price (StandardScaler)")
plt.show()                                           #죄석수 0이하 삭제이후 검토필요
In [62]:
renew_car_df = renew_car_df[renew_car_df["Engine_Encoded"] > 0].copy()
print(renew_car_df["Engine_Encoded"].describe())
count    3599.000000
mean        1.603779
std         0.485650
min         0.800000
25%         1.300000
50%         1.600000
75%         1.900000
max         6.300000
Name: Engine_Encoded, dtype: float64
In [66]:
sns.scatterplot(x=renew_car_df_standard["Engine_Encoded"], y=renew_car_df_standard["Price"])
plt.title("Engine Size vs Price (StandardScaler)")            #Engine_Encoded 4이상, 가격4이상 삭제
plt.show()
In [65]:
# Engine_Encoded 4 이상인 데이터 제거
renew_car_df = renew_car_df[renew_car_df["Engine_Encoded"] < 4].copy()
# 가격 30,000 이상인 데이터 제거
renew_car_df = renew_car_df[renew_car_df["Price"] < 30000].copy()

sns.scatterplot(x=renew_car_df["Engine_Encoded"], y=renew_car_df["Price"])
plt.title("Engine Size vs Price (Filtered)")
plt.show()                                   #Engine_Encoded와 가격과는 별다른 상관관계 찾기 어려움
In [67]:
# Seats가 0 이하인 행 제거
renew_car_df_standard = renew_car_df_standard[renew_car_df_standard["Seats"] > 0].copy()
# 좌석 수 vs 가격
sns.scatterplot(x=renew_car_df_standard["Seats"], y=renew_car_df_standard["Price"])
plt.title("Seats vs Price (StandardScaler)")
plt.show()
In [68]:
renew_car_df_standard = renew_car_df_standard[renew_car_df_standard["Seats"] > 0.5].copy()   #좌석수 0.5이하 삭제
# 좌석 수 vs 가격
sns.scatterplot(x=renew_car_df_standard["Seats"], y=renew_car_df_standard["Price"])
plt.title("Seats vs Price (Filtered, StandardScaler)")
plt.show()                              # 좌석수와 가격은 상관관계가 없는것으로 판단됨.
In [70]:
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# 3D Scatter Plot 
fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection='3d')
# 데이터 
x = renew_car_df_standard["Registration_Year"]  # 차량 연식
y = renew_car_df_standard["Emission_Class_Encoded"]  # 배출가스 등급
z = renew_car_df_standard["Price"]  # 가격
c = renew_car_df_standard["Mileage(miles)"]  # 주행거리 (색상으로 표현)
# 3D 산점도 
sc = ax.scatter(x, y, z, c=-c, cmap="coolwarm", alpha=0.7, s=20)
# 축 라벨 설정
ax.set_xlabel("Registration Year")
ax.set_ylabel("Emission Class Encoded")
ax.set_zlabel("Price")
ax.set_title("3D Scatter Plot: Registration Year, Emission Class, Mileage vs Price")
# 컬러바 추가 (주행거리)
cbar = fig.colorbar(sc, ax=ax, shrink=0.5)
cbar.set_label("Lower Mileage (Darker) / Higher Mileage (Lighter)")
plt.show()    
In [ ]:
# 등록연도가 최근, 배출가스 등급이 높은(친환경), 주행거리가 적을수록 차량가격이 높다.
# (특히 주행거리가 많을수록 가격이 떨어지는 경향이 높음)
In [71]:
country_brand_count = brand_df.groupby("country")["title"].nunique().reset_index()   #국가별 브랜드수
country_brand_count.columns = ["Country", "Total_Brands"]
print(country_brand_count)
           Country  Total_Brands
0   Czech Republic             1
1           France             4
2          Germany             6
3            Italy             4
4            Japan            11
5         Malaysia             1
6          Romania             1
7      South Korea             4
8            Spain             1
9           Sweden             2
10  United Kingdom             8
11   United States             5
In [72]:
# 숫자형 변수만 선택
numeric_cols = renew_car_df_standard.select_dtypes(include=[np.number])
# 상관계수 행렬 계산
corr_matrix = numeric_cols.corr()
# 상관계수 히트맵 시각화
plt.figure(figsize=(10, 6))
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", fmt=".2f", linewidths=0.5)
plt.title("Feature Correlation Matrix")
plt.show()
In [ ]:
#연식 Registration_Year 높을수록 차량 가격이 상승하는 경향이 강함 (0.69)
#주행거리가 많을수록(Mileage(miles)) 가격이 낮아지는 경향이 있음 (-0.50)
#배출가스 등급(Emission_Class_Encoded)이 높을수록(친환경?) 가격이 상승하는 경향이 있음 (0.57)