Imputing missing observations
Collecting data is messy. Research data collection instruments fail, humans do not want to answer some questions in a questionnaire, or files might get corrupted; these are but a sample of reasons why a dataset might have missing observations. If we want to use the dataset, we have a couple of choices: remove the missing observations altogether or replace them with some value.
Getting ready
To execute this recipe, you will need the pandas
module.
No other prerequisites are required.
How to do it…
Once again, we assume that the reader followed the earlier recipes and the csv_read
DataFrame is already accessible to us. To impute missing observations, all you need to do is add this snippet to your code (the data_imput.py
file):
# impute mean in place of NaNs csv_read['price_mean'] = csv_read['price'] \ .fillna( csv_read.groupby('zip')['price'].transform('mean') )
How it works…
The pandas
' .fillna(...)
method does all the heavy lifting for us. It is a DataFrame method that takes the value to be imputed as its only required parameter.
Tip
Consult the pandas
documentation of .fillna(...)
to see other parameters that can be passed to the method. The documentation can be found at http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.fillna.html.
In our approach, we assumed that each ZIP code might have different price averages. This is why we first grouped the observations using the .groupby(...)
method. It stands to reason that the prices of houses would also heavily depend on the number of rooms in a given house; if our dataset had more observations, we would have added the beds
variable as well.
The .groupby(...)
method returns a GroupBy
object. The .transform(...)
method of the GroupBy
object effectively replaces all the observations within ZIP code groups with a specified value, in our case, the mean for each ZIP code.
The .fillna(...)
method now simply replaces the missing observations with the mean of the ZIP code.
There's more…
Imputing the mean is not the only way to fill in the blanks. It returns a reasonable value only if the distribution of prices is symmetrical and without many outliers; if the distribution is skewed, the average is biased. A better metric of central tendency is the median. It takes one simple change in the way we presented earlier:
# impute median in place of NaNs csv_read['price_median'] = csv_read['price'] \ .fillna( csv_read.groupby('zip')['price'].transform('median') )