-
Notifications
You must be signed in to change notification settings - Fork 0
/
preprocessing_utils.py
271 lines (223 loc) · 12 KB
/
preprocessing_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
from common_utils import getMostFrequent
#NORMALIZZAZIONE
def normalizeDataset(df):
min_max_scaler = preprocessing.MinMaxScaler()
for k in df.columns:
df[k] = min_max_scaler.fit_transform(df[k].values.astype(float))
return df
def removeAttributes(df, removeBadBuy=False, *args):
#restituisce un dataframe ottenuto, a partire dal dataframe contenente tutti gli attributi
# rimuovendo tutti gli attributi che abbiamo deciso di rimuovere
# se @removeBadBuy =True, rimuove anche IsBadBuy dagli attributi del dataframe
try:
attributesToRemove = args[0]
print(attributesToRemove)
except IndexError:
attributesToRemove = ['RefId','VehYear','Model','SubModel','WheelTypeID','TopThreeAmericanName',\
'MMRAcquisitionAuctionAveragePrice','MMRAcquisitionAuctionCleanPrice',\
'MMRAcquisitionRetailAveragePrice','MMRAcquisitonRetailCleanPrice',\
'MMRCurrentAuctionAveragePrice','MMRCurrentAuctionCleanPrice',\
'MMRCurrentRetailCleanPrice','MMRCurrentRetailAveragePrice',
'PRIMEUNIT','AUCGUART','BYRNO','IsOnlineSale']
if removeBadBuy:
attributesToRemove.append('IsBadBuy')
return df.drop(attributesToRemove, axis=1)
def fillToOthers(attribute, df, **kwargs):
numDistinct = len(df[attribute].unique())
try:
topN = kwargs['topN']
except KeyError:
try:
valueToCut = kwargs['valueToCut']
numValues = sum(df[attribute].value_counts())
valuesToRepl=[]
for val in df[attribute].unique():
if float (len(df[df[attribute]==val]))/numValues < valueToCut:
valuesToRepl.append(val)
if len(valuesToRepl)>1:
df[attribute][df[attribute].isin(valuesToRepl)]='Others'
return df
except KeyError:
topN = 3
if numDistinct - topN > 1:
df[attribute][~df[attribute].isin(list(df[attribute].value_counts()[:topN].keys()))]='Others'
return df
def mapAttToInteger(attribute, df, removeOriginalAttribute=True):
attrValues = sorted(df[attribute].unique())
genders_mapping = dict(zip(attrValues, range(0, len(attrValues) + 1)))
df[str(attribute)+"Int"] = df[attribute].map(genders_mapping).astype(int)
if(removeOriginalAttribute):
del df[attribute]
return df
def discretizeAttribute(attribute, number_intervals, df, \
method='kmeans', removeOriginalAttribute=False):
# a partire dall'attributo @attribute del dataframe @dataframe, crea un nuovo attributo
# nominato "discretized@attribute" per il dataframe in input, sfruttando uno dei 3 possibili metodi:
# kmeans(default), equalFrequency o equalWidth. Tale attributo avrà n valori, dove n=@number_intervals
# in input; inoltre, se @removeOriginalAttribute =True, rimuove l'attributo originale, una volta creato
# quello discretizzato
discretizedAttributeName = 'discretized'+attribute[0].upper()+attribute[1:]
if method=='frequency':
df[discretizedAttributeName]=pd.qcut(df[attribute],number_intervals)
elif method=='width':
df[discretizedAttributeName]=pd.cut(df[attribute],number_intervals)
else:
dfTemp=pd.DataFrame(df[attribute])
attributeValues = dfTemp.values
kmeans = KMeans(init='k-means++', n_clusters=number_intervals, n_init=10, max_iter=100)
kmeans.fit(attributeValues)
df[discretizedAttributeName+"label"] = kmeans.labels_
df[discretizedAttributeName] = df[attribute]
df[discretizedAttributeName] = df[discretizedAttributeName].\
groupby(df[discretizedAttributeName+"label"]).apply\
(lambda x: x.replace (to_replace=x.unique(), \
value="[" + str(x.min()) + ", " + str(x.max()) +"]"))
del df[discretizedAttributeName+"label"]
if removeOriginalAttribute:
del df[attribute]
return df
def removeDays(date):
#restituisce la data ottenuta solo con mese e anno, rimuovendo quindi il giorno
splitted = str(date).split("/")
try:
month = splitted[0]
year = splitted[2]
newDate = month + "/" + year
return newDate
except:
return date
def getTrimester(date):
#a partire dalla data iniziale, restituisce il trimestre(1, 2, 3 o 4) e l'anno di appartenenza
splitted = str(date).split("/")
try:
month = splitted[0]
trimester = (int(month)-1)//3 + 1
year = splitted[2]
dateToTrimester = str(trimester) + "/" + year
return dateToTrimester
except:
return date
def sizeMapping(df):
sizes = df['Size']
sizes [df['Size'].isin(['MEDIUM SUV','CROSSOVER'])]='MEDIUM'
sizes [df['Size'].isin(['SMALL TRUCK','LARGE TRUCK','VAN'])]='LARGE'
sizes [df['Size'].isin(['SPECIALTY'])]='SPORTS'
sizes [df['Size'].isin(['SMALL SUV'])]='COMPACT'
return sizes
def replaceMissingValues(df, replaceSize=True, **kwargs):
#RISOLUZIONE MISSING VALUES TRIM PER IL DATAFRAME IN INPUT
""" SOSTITUISCO I VALORI DEI MISSING VALUES DI TRIM CON I VALORI
DI TRIM PIÙ FREQUENTI AVENTI COME MODELLO E SOTTOMODELLO QUELLO DELL'OGGETTO
PER CUI TRIM E' MISSING VALUES: ad es.:
Ferrari(Make) Enzo(Model) 5000GT(SubModel), trim come miss.value.
Vedo i trim associati agli oggetti aventi Enzo come Model e
5000GT come SubModel e quindi prendo il più frequente di questi
e lo sostituisco all'oggetto avente Trim come missing value """
df ["Trim"] = df ["Trim"].groupby([df["Model"],df["SubModel"]]).apply \
(lambda x: x.fillna(getMostFrequent(x)))
# Se dopo aver sostituito i valori più frequenti dei Sottomodelli,
# ci sono ancora missing values, allora:
# SOSTITUISCO I VALORI DEI MISSING VALUES DI TRIM CON I VALORI
# DI TRIM PIÙ FREQUENTI AVENTI COME MODELLO QUELLO DELL'OGGETTO
# PER CUI TRIM E' MISSING VALUES: ad es.:
# Ferrari(Make) Enzo(Model), trim e SubModel come miss.value
# (per questo motivo devo analizzare Model e non posso analizzare SubModel).
# Vedo i trim associati agli oggetti aventi Enzo come Model
# e quindi prendo il più frequente di questi e lo sostituisco
# all'oggetto avente Trim come missing value
if len(df [df.Trim.isnull()])>0:
df ["Trim"] = df ["Trim"].groupby(df["Model"]).apply \
(lambda x: x.fillna(getMostFrequent(x)))
# Se ancora ci sono missing values per trim, li sostituisco
#con il valore più frequente per l'intero dataset.
if len(df [df.Trim.isnull()])>0:
df.Trim = df.Trim.fillna(getMostFrequent(df.Trim))
#RISOLUZIONE MISSING VALUES COLOR PER IL DATAFRAME IN INPUT
""" Rimpiazzo i NOT AVAIL con i NAN, quindi rimpiazzo tutti i missing values(NAN)
con il valore più frequente di color nell'intero dataset """
df ["Color"] [df["Color"]=='NOT AVAIL'] = df["Color"].map(lambda x: np.nan)
df["Color"] = df["Color"].fillna(getMostFrequent(df["Color"]))
#RISOLUZIONE MISSING VALUES SIZE PER IL DATAFRAME IN INPUT
""" Sostituisco i miss values di Size, sfruttando i valori di Model.
Per ogni model, infatti, c'è quasi sempre una sola size associata, quindi Model
è un ottimo modo per discriminare le diverse size. Quindi sostituisco i missing values
di size con il valore più frequente di size associato ad un certo model.
Se non vi sono valori per Size di un certo Model nel dataset,
prendo il valore più frequente di Size nell'intero dataset."""
df["Size"] = df["Size"].groupby(df["Model"]).apply\
(lambda x: x.fillna(getMostFrequent(x)))
if len(df [df["Size"].isnull()]) > 0:
df["Size"] = df["Size"].fillna(getMostFrequent(df["Size"]))
#RISOLUZIONE MISSING VALUES NATIONALITY PER IL DATAFRAME IN INPUT
""" Rimpiazzo i missing values di Nationality sfruttando il valore di
make degli oggetti: ad ogni make è associato sostanzialmente
sempre un solo valore per nationality. In ogni caso, se per un make
nel dataset ci sono più valori per nationality, prendo quello più
frequente e uso quello """
df["Nationality"] = df["Nationality"].groupby(df["Make"]).apply \
(lambda x: x.fillna(getMostFrequent(x)))
if len(df [df["Nationality"].isnull()]) > 0:
df["Nationality"] = df["Nationality"].fillna\
(getMostFrequent(df["Nationality"]))
if replaceSize:
df['Sizes'] = sizeMapping(df)
#RISOLUZIONE MISSING VALUES WHEELTYPE PER IL DATAFRAME IN INPUT
""" Rimpiazzo i missing values di WheelType sfruttando il valore di Size.
Infatti ho notato una netta differenza di bilanciamento dei valori di WheelType, per le
diverse size nel dataset. Per alcune Size, la grande maggioranza sono Covers, per
un'altra Size, la grande maggioranza sono Special, e per altre ancorad
troviamo una maggioranza di Alloy. Ciò è anche abbastanza comprensibile, dato che per un
suv difficilmente troveremo "cerchi comuni", per una sportiva molto più probabilmente
troveremo dei cerchi "Special", mentre per un'utilitaria troveremo spesso
dei cerchi "comuni"(Alloy). """
df["WheelType"] = df["WheelType"].groupby(df["Size"]).apply \
(lambda x: x.fillna(getMostFrequent(x)))
if len(df [df["WheelType"].isnull()]) > 0:
df["WheelType"] = df["WheelType"].fillna\
(getMostFrequent(df["WheelType"]))
#RISOLUZIONE MISSING VALUES TRANSMISSION PER IL DATAFRAME IN INPUT
""" Sostituisco tutti i valori di Transmission con il loro valore in maiuscolo
nel dataset infatti ci sono oggetti con 'Manual' ed oggetti con 'MANUAL' """
df['Transmission'] = df["Transmission"][df["Transmission"].notnull()]\
.map(lambda x: str(x).upper())
df["Transmission"] = df["Transmission"].fillna(getMostFrequent(df["Transmission"]))
#RIMPIAZZO PREZZI UGUALI A 0 O A 1 CON NAN, PER IL DATAFRAME IN INPUT
"""Sostituisco tutti gli 0 per i vari prezzi con nan
inoltre sostituisco tutti gli 1 con nan per MMRCurrentRetailAveragePrice. """
df['MMRCurrentRetailAveragePrice'] [df['MMRCurrentRetailAveragePrice']==0.0] = df['MMRCurrentRetailAveragePrice'].map(lambda x: np.nan)
df ['MMRAcquisitionAuctionCleanPrice'] [df.MMRAcquisitionAuctionCleanPrice.isin ([0.0,1.0])] = df.MMRAcquisitionAuctionCleanPrice.map(lambda x: np.nan)
df ['MMRAcquisitionRetailAveragePrice'] [df.MMRAcquisitionRetailAveragePrice==0] = df.MMRAcquisitionRetailAveragePrice.map(lambda x: np.nan)
df ['MMRAcquisitonRetailCleanPrice'] [df.MMRAcquisitonRetailCleanPrice==0] = df.MMRAcquisitonRetailCleanPrice.map(lambda x: np.nan)
try:
dates = kwargs['dates']
#RISOLUZIONE MISSING VALUES MMRCurrentRetailAveragePrice PER IL DATAFRAME IN INPUT
df['MMRCurrentRetailAveragePriceFill'] = \
df.MMRCurrentRetailAveragePrice.groupby\
([dates, df.Model,df.SubModel]).apply\
(lambda x: x.replace(to_replace=np.nan, value=x.median()))
df['MMRCurrentRetailAveragePriceFill'] = \
df.MMRCurrentRetailAveragePriceFill.groupby \
([dates, df.Model]).apply \
(lambda x: x.replace(to_replace=np.nan, value=x.median()))
df['MMRCurrentRetailAveragePriceFill'] = \
df.MMRCurrentRetailAveragePriceFill.groupby \
([dates, df.Make]).apply \
(lambda x: x.replace(to_replace=np.nan, value=x.median()))
df['PurchDate'] = dates
except (KeyError, ValueError):
df['MMRCurrentRetailAveragePriceFill'] = \
df.MMRCurrentRetailAveragePrice.groupby\
([df['PurchDate'], df.Model,df.SubModel]).apply\
(lambda x: x.replace(to_replace=np.nan, value=x.median()))
df['MMRCurrentRetailAveragePriceFill'] = \
df.MMRCurrentRetailAveragePriceFill.groupby \
([df['PurchDate'], df.Model]).apply \
(lambda x: x.replace(to_replace=np.nan, value=x.median()))
df['MMRCurrentRetailAveragePriceFill'] = \
df.MMRCurrentRetailAveragePriceFill.groupby \
([df['PurchDate'], df.Make]).apply \
(lambda x: x.replace(to_replace=np.nan, value=x.median()))
return df