第一部分探索数据

 提供在Python中清理数据所需的所有技能,从学习如何诊断问题数据到处理缺失值和异常值。

所以你刚刚得到了一个全新的数据集,并且渴望开始探索它。 但是你从哪里开始,你怎么能确定你的数据集是干净的? 本章将向您介绍Python中的数据清理世界! 您将学习如何探索数据,以便诊断异常值,缺失值和重复行等问题。

Python数据清洗替换 python 清洗数据_数据

 

1、加载和查看数据
在本章中,将查看来自NYC Open Data门户的建筑署工作申请文件数据集的子集。该数据集包括2017年1月22日提交的工作申请。第一个任务是将此数据集加载到DataFrame中,然后使用.head()和.tail()方法对其进行检查。但是,很快发现打印结果不允许您查看所需的所有内容,因为列太多了。因此,您需要以另一种方式查看数据。

使用.shape和.columns属性可以查看DataFrame的形状并获取其列的列表。从这里,您可以看到哪些列与您想要询问的数据相关。为此,已预先加载了仅包含这些相关列的新DataFrame,df_subset。这是将在本章其余部分使用的DataFrame。

现在通过使用pandas探索数据集、熟悉数据集!最初的探索性分析是数据清理的关键第一步。

# Import pandas
import pandas as pd

# Read the file into a DataFrame: df
df = pd.read_csv('dob_job_application_filings_subset.csv')

#df2 = df[['Job #', 'Doc #', 'Borough', 'Initial Cost', 'Total Est. Fee','Existing Zoning Sqft', 'Proposed Zoning Sqft','Enlargement SQ Footage', 'Street Frontage', 'ExistingNo. of Stories','Proposed No. of Stories', 'Existing Height', 'Proposed Height']]
# Print the head of df
print(df.head())

# Print the tail of df
print(df.tail())

# Print the shape of df
print(df.shape)

# Print the columns of df
print(df.columns)

# Print the head and tail of df_subset
print(df_subset.head())
print(df_subset.tail())
#print(df2.equals(df_subset))

如下为df_subset的DataFrame, [12846 rows x 13 columns]

'Job #', 'Doc #', 'Borough', 'Initial Cost', 'Total Est. Fee','Existing Zoning Sqft', 'Proposed Zoning Sqft','Enlargement SQ Footage', 'Street Frontage', 'ExistingNo. of Stories','Proposed No. of Stories', 'Existing Height', 'Proposed Height'

      Initial Cost Total Est. Fee
0        $75000.00        $986.00
1            $0.00       $1144.00
2        $30000.00        $522.50
3         $1500.00        $225.00
4        $19500.00        $389.50

           Job #       ...         Proposed Height
0      121577873       ...                       0
1      520129502       ...                       0
2      121601560       ...                      54
3      121601203       ...                     120
4      121601338       ...                      64
5      121589753       ...                    1250
6      320738001       ...                      36
7      121601374       ...                     300
8      121583054       ...                     398
9      121601392       ...                      16
10     121601169       ...                      60
11     420828206       ...                      28
12     420828493       ...                      15
13     440075142       ...                      12
14     420836723       ...                      15
15     121584525       ...                       0
16     121600311       ...                      75
17     320744290       ...                      52
18     320744557       ...                      24
19     320744370       ...                      25
20     220286232       ...                     101
21     121599779       ...                     520
22     420837401       ...                      26
23     220286287       ...                      60
24     240024362       ...                     180
25     320744316       ...                      33
26     121601249       ...                       0
27     121592605       ...                     546
28     121577873       ...                     200
29     520129496       ...                      15
...          ...       ...                     ...
12816  121675188       ...                     210
12817  520143942       ...                      15
12818  320833586       ...                      74
12819  220307406       ...                       0
12820  121641312       ...                      60
12821  140087322       ...                     165
12822  121680859       ...                     160
12823  121678167       ...                      99
12824  320721206       ...                       0
12825  121681019       ...                      42
12826  520143862       ...                      37
12827  520143933       ...                      29
12828  320723160       ...                      29
12829  420857022       ...                      30
12830  420857077       ...                      30
12831  220307433       ...                      20
12832  320590552       ...                      39
12833  420606865       ...                       0
12834  121681135       ...                      30
12835  121632331       ...                     170
12836  121681108       ...                     190
12837  121330087       ...                       0
12838  140087420       ...                     150
12839  440089538       ...                      45
12840  420606865       ...                       0
12841  520143988       ...                      10
12842  121613833       ...                      55
12843  121681260       ...                      64
12844  320771704       ...                      18
12845  520143951       ...                      18

可以看出有很多0值,而且Initial Cost和 Total Est. Fee的数值前面都有个‘$’

2、进一步诊断
在上一步中,确定了一些可能不干净或缺失的数据。 现在,继续使用非常有用的.info()方法诊断数据。

.info()方法提供有关DataFrame的重要信息,例如行数,列数,每列中的非缺失值数以及每列中存储的数据类型。

这种信息可以让您确认“ 'Initial Cost'”和“'Total Est. Fee'”。 费用列是数字或字符串。 从结果中,您还可以查看所有列是否都包含完整数据。

# Print the info of df
print(df.info())

# Print the info of df_subset
print(df_subset.info())

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12846 entries, 0 to 12845
Data columns (total 82 columns):
Job #                           12846 non-null int64
Doc #                           12846 non-null int64
Borough                         12846 non-null object
House #                         12846 non-null object
Street Name                     12846 non-null object
Block                           12846 non-null int64
Lot                             12846 non-null int64
Bin #                           12846 non-null int64
Job Type                        12846 non-null object
Job Status                      12846 non-null object
Job Status Descrp               12846 non-null object
Latest Action Date              12846 non-null object
Building Type                   12846 non-null object
Community - Board               12846 non-null object
Cluster                         0 non-null float64
Landmarked                      2067 non-null object
Adult Estab                     1 non-null object
Loft Board                      65 non-null object
City Owned                      1419 non-null object
Little e                        365 non-null object
PC Filed                        0 non-null float64
eFiling Filed                   12846 non-null object
Plumbing                        12846 non-null object
Mechanical                      12846 non-null object
Boiler                          12846 non-null object
Fuel Burning                    12846 non-null object
Fuel Storage                    12846 non-null object
Standpipe                       12846 non-null object
Sprinkler                       12846 non-null object
Fire Alarm                      12846 non-null object
Equipment                       12846 non-null object
Fire Suppression                12846 non-null object
Curb Cut                        12846 non-null object
Other                           12846 non-null object
Other Description               12846 non-null object
Applicant's First Name          12846 non-null object
Applicant's Last Name           12846 non-null object
Applicant Professional Title    12846 non-null object
Applicant License #             12846 non-null object
Professional Cert               6908 non-null object
Pre- Filing Date                12846 non-null object
Paid                            11961 non-null object
Fully Paid                      11963 non-null object
Assigned                        3817 non-null object
Approved                        4062 non-null object
Fully Permitted                 1495 non-null object
Initial Cost                    12846 non-null object
Total Est. Fee                  12846 non-null object
Fee Status                      12846 non-null object
Existing Zoning Sqft            12846 non-null int64
Proposed Zoning Sqft            12846 non-null int64
Horizontal Enlrgmt              231 non-null object
Vertical Enlrgmt                142 non-null object
Enlargement SQ Footage          12846 non-null int64
Street Frontage                 12846 non-null int64
ExistingNo. of Stories          12846 non-null int64
Proposed No. of Stories         12846 non-null int64
Existing Height                 12846 non-null int64
Proposed Height                 12846 non-null int64
Existing Dwelling Units         12846 non-null object
Proposed Dwelling Units         12846 non-null object
Existing Occupancy              12846 non-null object
Proposed Occupancy              12846 non-null object
Site Fill                       8641 non-null object
Zoning Dist1                    11263 non-null object
Zoning Dist2                    1652 non-null object
Zoning Dist3                    88 non-null object
Special District 1              3062 non-null object
Special District 2              848 non-null object
Owner Type                      0 non-null float64
Non-Profit                      971 non-null object
Owner's First Name              12846 non-null object
Owner's Last Name               12846 non-null object
Owner's Business Name           12846 non-null object
Owner's House Number            12846 non-null object
Owner'sHouse Street Name        12846 non-null object
City                            12846 non-null object
State                           12846 non-null object
Zip                             12846 non-null int64
Owner'sPhone #                  12846 non-null int64
Job Description                 12699 non-null object
DOBRunDate                      12846 non-null object
dtypes: float64(3), int64(15), object(64)
memory usage: 8.0+ MB
None
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12846 entries, 0 to 12845
Data columns (total 13 columns):
Job #                      12846 non-null  int64
Doc #                      12846 non-null int64
Borough                    12846 non-null object
Initial Cost               12846 non-null object
Total Est. Fee             12846 non-null object
Existing Zoning Sqft       12846 non-null int64
Proposed Zoning Sqft       12846 non-null int64
Enlargement SQ Footage     12846 non-null int64
Street Frontage            12846 non-null int64
ExistingNo. of Stories     12846 non-null int64
Proposed No. of Stories    12846 non-null int64
Existing Height            12846 non-null int64
Proposed Height            12846 non-null int64
dtypes: int64(10), object(3)
memory usage: 1.3+ MB
None
注意到列“Initial Cost”和“Total Est. Fee ”。 其类型是对象。因此, 需要删除这些列中每个值开头的货币符号,并且需要将列值转换为数字。 在完整的DataFrame中,注意有很多缺失值。 在上一个练习中看到,还有很多0值。 鉴于完整数据集中缺少的数据量,这些0值很可能代表缺失的数据。

假设已经将df.subset 中的列“Initial Cost”和“Total Est. Fee ”数值化了。

In [1]: df.describe()
Out[1]: 
              Job #       ...         Proposed Height
count  1.284600e+04       ...            12846.000000
mean   2.426788e+08       ...               94.917562
std    1.312507e+08       ...              146.580666
min    1.036438e+08       ...                0.000000
25%    1.216206e+08       ...               21.000000
50%    2.202645e+08       ...               45.000000
75%    3.208652e+08       ...              107.000000
max    5.400246e+08       ...             4200.000000

[8 rows x 12 columns],本来有13列,df.describe()后少了一列。

3、分类数据的频率计数

如您所见,.describe()只能用于数字列。 那么,当您有其他数据时,如何诊断数据问题?

一种方法是使用.value_counts()方法,该方法返回列中每个唯一值的频率计数!

此方法还有一个名为dropna的可选参数,默认情况下为True。 这意味着如果您在列中缺少数据,它将不会给出它们的频率计数。 您希望将dropna列设置为False,因此如果列中缺少值,它将为您提供频率计数。

# Print the value counts for 'Borough'
print(df['Borough'].value_counts(dropna=False))

# Print the value_counts for 'State'
print(df.State.value_counts(dropna=False))

# Print the value counts for 'Site Fill'
print(df['Site Fill'].value_counts(dropna=False))

MANHATTAN        6310
BROOKLYN         2866
QUEENS           2121
BRONX             974
STATEN ISLAND     575
Name: Borough, dtype: int64

NY    12391
NJ      241
PA       38
CA       20
OH       19
FL       17
IL       17
CT       16
TX       13
TN       10
MD        7
DC        7
MA        6
GA        6
KS        6
VA        5
CO        4
WI        3
SC        3
AZ        3
MN        3
UT        2
RI        2
NC        2
WA        1
NM        1
IN        1
VT        1
MI        1
Name: State, dtype: int64

NOT APPLICABLE                              7806
NaN                                         4205
ON-SITE                                      519
OFF-SITE                                     186
USE UNDER 300 CU.YD                          130
Name: Site Fill, dtype: int64

请注意“State”列中的所有值不都是NY。 这是一个有趣的发现,因为这些数据应该包含在纽约市提交的申请。
奇怪的是,所有'Borough'值都是正确的。关于为什么会出现这种情况的一个良好开端是找到并查看该数据集的代码簿。

此外,对于“Site Fill”列,可能需要或可能不需要在最终分析中将NOT APPLICABLE值重新编码为NaN。

4、视觉探索性数据分析---发现异常值和明显错误的好方法

到目前为止,一直在查看数据的描述性统计信息。 确认数字的最佳方法之一是绘制和可视化数据。

4.1使用直方图可视化单个变量

首先,使用直方图可视化单个变量的数值。 在本练习中处理的列是“Existing Zoning Sqft”。

# Import matplotlib.pyplot
import matplotlib.pyplot as plt

# Describe the column
df['Existing Zoning Sqft'].describe()

# Plot the histogram
df['Existing Zoning Sqft'].plot(kind='hist', rot=70, logx=True, logy=True)

# Display the histogram
plt.show()

count    1.284600e+04
mean     1.439973e+03
std      3.860757e+04
min      0.000000e+00
25%      0.000000e+00
50%      0.000000e+00
75%      0.000000e+0

max      2.873107e+06
Name: Existing Zoning Sqft, dtype: float64

可以看出‘Existing Zoning Sqft’列,最大值和最小值相差很大

Python数据清洗替换 python 清洗数据_python_02

虽然可视化数据是理解它的好方法,但请记住,没有一种技术比另一种更好。  正如在此处所看到的,仍需要查看摘要统计信息,以便更好地了解数据。你期望在图的左侧有大量的计数,因为第25,第50和第75百分位数的值为0.该图显示我们几乎没有任何计数接近最大值,表示为异常值。

4.2 使用箱线图可视化多个变量

直方图是可视化单个变量的好方法。 为了可视化多个变量,箱线图很有用,尤其是当其中一个变量是分类变量时。

# Import necessary modules
import pandas as pd
import matplotlib.pyplot as plt

# Create the boxplot
df.boxplot(column='initial_cost', by='Borough', rot=90)

# Display the plot
plt.show()

Python数据清洗替换 python 清洗数据_Python数据清洗替换_03

你可以看到2个极端异常值在曼哈顿区。 最初的猜测可能是,由于曼哈顿的土地非常昂贵,这些异常值可能是有效的数据点。 同样,需要进一步调查以确定是否可以删除或保留数据中的这些点。

4.3 使用散点图可视化多个变量

箱线图适合在不同类别之间进行比较的数字列(一列为数字,一列不是数字)。 当您想要显示两个数字列时,散点图是理想的。
 

# Import necessary modules
import pandas as pd
import matplotlib.pyplot as plt

# Create and display the first scatter plot
df.plot(kind='scatter', x='initial_cost', y='total_est_fee', rot=70)
plt.show()

# Create and display the second scatter plot
df_subset.plot(kind='scatter', x='initial_cost', y='total_est_fee', rot=70)
plt.show()

Python数据清洗替换 python 清洗数据_数据_04

Python数据清洗替换 python 清洗数据_数据清洗_05

从第二个图来看,似乎'initial_cost'和'total_est_fee'之间存在很强的相关性。 另外,请注意“initial_cost”为0的大量点。很难从第一个图中推断出任何趋势,因为它由异常值控制。