a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a)
df.dtypes
# 0 object
# 1 object
# 2 object
# dtype: object
如何修改第2、3列的类型?扩展一下,如果有很多列的时候,如何高效的修改?
Pandas中主要有4种类型转换相关的方法:
to_numeric/to_datetime/to_timedelta
:可以参数转换为合适的对应类型。astype
infer_objects
convert_dtypes
to_numeric
将参数转换为合适的数值类型(float64/int64)。签名如下:
pandas.to_numeric(arg, errors='raise', downcast=None)
先看一些使用例子:
In [2]: s = pd.Series(["8", 6, "7.5", 3, "0.9"])
In [3]: s
Out[3]:
0 8
1 6
2 7.5
3 3
4 0.9
dtype: object
In [4]: pd.to_numeric(s)
Out[4]:
0 8.0
1 6.0
2 7.5
3 3.0
4 0.9
dtype: float64
可以使用apply()
方法批量转换DataFrame里面的列:
In [11]: df = pd.DataFrame([['1', '2', '3'],['4', '5', '6'],['7.1', '8.0', '9']], columns=['a','b', 'c'])
In [12]: df
Out[12]:
a b c
0 1 2 3
1 4 5 6
2 7.1 8.0 9
In [13]: df.dtypes
Out[13]:
a object
b object
c object
dtype: object
In [14]: df_1=df.apply(pd.to_numeric)
In [15]: df_1
Out[15]:
a b c
0 1.0 2.0 3
1 4.0 5.0 6
2 7.1 8.0 9
In [16]: df_1.dtypes
Out[16]:
a float64
b float64
c int64
dtype: object
也可以只对某些列进行转换:
In [18]: df[['a','b']]=df[['a','b']].apply(pd.to_numeric)
In [19]: df
Out[19]:
a b c
0 1.0 2.0 3
1 4.0 5.0 6
2 7.1 8.0 9
In [20]: df.dtypes
Out[20]:
a float64
b float64
c object
dtype: object
类型转换难免会产生错误,比如无法转换等,to_numeric
提供了一个参数errors
来让用户控制发生错误时如何处理,用有三个选项:
看一些例子:
In [21]: df=pd.DataFrame([['1','2'],['3','4'],['5','s']], columns=['a','b'])
In [22]: df
Out[22]:
a b
0 1 2
1 3 4
2 5 s
In [23]: df.dtypes
Out[23]:
a object
b object
dtype: object
In [24]: df.apply(pd.to_numeric)
ValueError: Unable to parse string "s" at position 2
In [25]: df.apply(pd.to_numeric, errors='coerce')
Out[25]:
a b
0 1 2.0
1 3 4.0
2 5 NaN
In [26]: df.apply(pd.to_numeric, errors='ignore')
Out[26]:
a b
0 1 2
1 3 4
2 5 s
to_numeric
默认会转换为float64或者int64,如果你想节省内存转换为小一些的类型的话,可以使用to_numeric提供的downcast
参数,可选值如下:
看一些例子:
In [29]: s = pd.Series(['1','2','-7'])
In [30]: s
Out[30]:
0 1
1 2
2 -7
dtype: object
In [31]: pd.to_numeric(s)
Out[31]:
0 1
1 2
2 -7
dtype: int64
In [32]: pd.to_numeric(s, downcast='integer')
Out[32]:
0 1
1 2
2 -7
dtype: int8
# 注意这里:因为 unsigned无法表示-7,所以这里实际没有发生downcast
In [33]: pd.to_numeric(s, downcast='unsigned')
Out[33]:
0 1
1 2
2 -7
dtype: int64
In [34]: pd.to_numeric(s, downcast='float')
Out[34]:
0 1.0
1 2.0
2 -7.0
dtype: float32
这里有2个注意点:
errors
参数对downcast这里是无效的。如果目标类型无法容纳被转换的值,就不会发生实际的转换。比如上面尝试转换为'unsigned'类型时,因为-7无法转换为unsigned,所以实际没有执行downcast。
to_datetime
把参数转换为datetime类型,相比于to_numeric
,函数原型复杂了一些。
pandas.to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix', cache=True)
看一些使用例子:
# 可以使用这些关键字来构造表示时间日期的字典:[‘year’, ‘month’, ‘day’, ‘minute’, ‘second’, ‘ms’, ‘us’, ‘ns’]),复数也可以
In [35]: df = pd.DataFrame({'year': [2015, 2016], 'month': [2, 3], 'day':[4, 5]})
In [36]: df
Out[36]:
2016 3 5
In [37]: df.dtypes
Out[37]:
year int64
month int64
day int64
dtype: object
In [38]: pd.to_datetime(df)
Out[38]:
2016-03-05
dtype: datetime64[ns]
In [40]: pd.to_datetime(1490195805, unit='s')
Out[40]: Timestamp('2017-03-22 15:16:45')
In [41]: pd.to_datetime(1490195805433502912, unit='ns')
Out[41]: Timestamp('2017-03-22 15:16:45.433502912')
In [42]: pd.to_datetime("10/11/12", dayfirst=True)
Out[42]: Timestamp('2012-11-10 00:00:00')
In [43]: pd.to_datetime("10/11/12", yearfirst=True)
Out[43]: Timestamp('2010-11-12 00:00:00')
In [44]: pd.to_datetime("10/11/12", dayfirst=True, yearfirst=True)
Out[44]: Timestamp('2010-12-11 00:00:00')
`errors`字段含义同`to_numeric`:
看个例子:
In [46]: pd.Timestamp.min
Out[46]: Timestamp('1677-09-21 00:12:43.145225')
In [47]: pd.Timestamp.max
Out[47]: Timestamp('2262-04-11 23:47:16.854775807')
In [48]: pd.to_datetime('13000101', format='%Y%m%d', errors='raise')
OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1300-01-01 00:00:00
In [49]: pd.to_datetime('13000101', format='%Y%m%d', errors='ignore')
Out[49]: datetime.datetime(1300, 1, 1, 0, 0)
In [50]: pd.to_datetime('13000101', format='%Y%m%d', errors='coerce')
Out[50]: NaT
In [53]: pd.to_datetime('130000101', format='%Y%m%d', errors='ignore')
Out[53]: '130000101'
timedelta类型表示两个时间的绝对差值,to_timedelta
将参数转换为timedelta类型。方法签名如下:
pandas.to_timedelta(arg, unit=None, errors='raise')
unit
用于指定参数的单位,默认为ns
,合法的取值如下:
errors
的取值同to_datetime
。看几个使用例子:
In [55]: pd.to_timedelta('1 days 06:05:01.00003')
Out[55]: Timedelta('1 days 06:05:01.000030')
In [56]: pd.to_timedelta('15.5us')
Out[56]: Timedelta('0 days 00:00:00.000015500')
In [57]: pd.to_timedelta(['1 days 06:05:01.00003', '15.5us', 'nan'])
Out[57]: TimedeltaIndex(['1 days 06:05:01.000030', '0 days 00:00:00.000015500', NaT], dtype='timedelta64[ns]', freq=None)
In [58]: import numpy as np
In [59]: pd.to_timedelta(np.arange(5), unit='s')
Out[59]:
TimedeltaIndex(['0 days 00:00:00', '0 days 00:00:01', '0 days 00:00:02',
'0 days 00:00:03', '0 days 00:00:04'],
dtype='timedelta64[ns]', freq=None)
In [60]: pd.to_timedelta(np.arange(5), unit='d')
Out[60]: TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq=None)
astype方法可以做任意类型的转换(当然未必能成功)。方法原型如下:
pd.DataFrame.astype(dtype, copy=True, errors='raise')
dtype
就是我们想要转换成的目标类型,可以使用Numpy的类型、Python的部分类型、Pandas特有的类型。copy
表示是否修改原数据。errors
可以取'raise'(失败是抛异常)或者'ignore'(失败时忽略并返回原值)。
看一些例子:
In [62]: df = pd.DataFrame({'col1': [1, 2], 'col2': [3, 4]})
In [63]: df.dtypes
Out[63]:
col1 int64
col2 int64
dtype: object
In [64]: df.astype('int32').dtypes
Out[64]:
col1 int32
col2 int32
dtype: object
In [65]: s = pd.Series([1, 3], dtype='int32')
In [66]: s
Out[66]:
0 1
1 3
dtype: int32
In [67]: s.astype('int64')
Out[67]:
0 1
1 3
dtype: int64
In [68]: s.astype('category')
Out[68]:
0 1
1 3
dtype: category
Categories (2, int64): [1, 3]
In [77]: s_date = pd.Series(['20220101', '20220102', '20220103'])
In [78]: s_date
Out[78]:
0 20220101
1 20220102
2 20220103
dtype: object
In [79]: s_date.astype('datetime64')
Out[79]:
0 2022-01-01
1 2022-01-02
2 2022-01-03
dtype: datetime64[ns]
In [81]: i = pd.Series([1,2,3])
In [82]: i
Out[82]:
0 1
1 2
2 3
dtype: int64
In [83]: i.astype(str)
Out[83]:
0 1
1 2
2 3
dtype: object
In [84]: s = pd.Series([1,2,-7])
In [85]: s.astype(np.int8)
Out[85]:
0 1
1 2
2 -7
dtype: int8
In [86]: s.astype(np.uint8)
Out[86]:
0 1
1 2
2 249
dtype: uint8
使用astype的时候,要注意范围,比如下面的转换不会报错,但不是我们想要的:
In [95]: s = pd.Series([1,2,-7])
# -7被转换为249
In [96]: s.astype(np.uint8)
Out[96]:
0 1
1 2
2 249
dtype: uint8
# 使用to_numeric就不会有问题
In [97]: pd.to_numeric(s, downcast='unsigned')
Out[97]:
0 1
1 2
2 -7
dtype: int64
pandas 0.21.0版本加入,会尝试推测类型。看个例子:
In [103]: df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
In [104]: df.dtypes
Out[104]:
a object
b object
dtype: object
In [105]: df.infer_objects().dtypes
Out[105]:
a int64
b object
dtype: object
可以看到,infer_objects
其实还是比较“肤浅”的,如果要将'b'列也转换成数值型,可以使用前面介绍的方法。
convert_dtypes
会尝试将各列转换为最可能的类型,其特点是支持pd.NA
,方法签名如下:
DataFrame.convert_dtypes(infer_objects=True, convert_string=True, convert_integer=True, convert_boolean=True, convert_floating=True)
通过各个类型参数可以控制某些类型是否转换;infer_objects
为True时会尝试转换object类型为更具体的类型。看一些例子:
In [110]: df = pd.DataFrame(
...: {
...: 'a': pd.Series([1, 2, 3], dtype=np.dtype('int32')),
...: 'b': pd.Series(['x', 'y', 'z'], dtype=np.dtype('O')),
...: 'c': pd.Series([True, False, np.nan], dtype=np.dtype('O')),
...: 'd': pd.Series(['h', 'i', np.nan], dtype=np.dtype('O')),
...: 'e': pd.Series([10, np.nan, 20], dtype=np.dtype('float')),
...: 'f': pd.Series([np.nan, 100.5, 200], dtype=np.dtype('float')),
...: }
...: )
In [111]: df
Out[111]:
a b c d e f
0 1 x True h 10.0 NaN
1 2 y False i NaN 100.5
2 3 z NaN NaN 20.0 200.0
In [112]: df.dtypes
Out[112]:
a int32
b object
c object
d object
e float64
f float64
dtype: object
In [113]: dfn = df.convert_dtypes()
In [114]: dfn
Out[114]:
a b c d e f
0 1 x True h 10 NaN
1 2 y False i <NA> 100.5
2 3 z <NA> <NA> 20 200.0
In [115]: dfn.dtypes
Out[115]:
a Int32
b string
c boolean
d string
e Int64
f float64
dtype: object
End, that's all!
]]>Pandas是Python中一个高性能库,提供了非常易用的数据结构以及丰富的函数工具用来做数据分析,所以该库在数据分析领域用的非常广泛。使用Pandas的关键点在于理解Pandas的两个核心数据结构:Series和DataFrame。
Series表示带有标签的一维数组(one-dimensional labeled array):
构造Series结构最常用的方式就是使用pandas.Series
类,参数及说明如下:
pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)
下面列举几个创建Series的例子。
In [1]: import pandas as pd
In [2]: import numpy as np
# 使用数组创建Series,并指定index
In [3]: arr = np.array([1,2,3,4,5])
In [4]: s = pd.Series(arr, index=['a','b','c','d','a'])
In [5]: s
Out[5]:
a 1
b 2
c 3
d 4
a 5
dtype: int64
In [6]: s.index
Out[6]: Index(['a', 'b', 'c', 'd', 'a'], dtype='object')
# 使用数组创建Series,且使用默认的index
In [7]: pd.Series(np.random.randn(5))
Out[7]:
0 -1.316523
1 -1.211854
2 -0.532214
3 -0.143331
4 0.335070
dtype: float64
# 通过字典创建Series
In [8]: d = {'b':1, 'a':0, 'c':2}
In [9]: pd.Series(d)
Out[9]:
a 0
b 1
c 2
dtype: int64
# 使用标量创建Series,要注意此时标量重复len(index)次
In [10]: pd.Series(5., index=['a','b','c','d','e'])
Out[10]:
a 5.0
b 5.0
c 5.0
d 5.0
e 5.0
dtype: float64
在时间序列预测中Series数据结构将非常有用。
DataFrame和Series类似,但DataFrame是二维的,非常类似于关系型数据库里面的表。我们一般把列标签依旧称为index,而把行标签称为Column,对应的也有着两个参数去指定行列标签。DataFrame对象的构造方法和Series极其类似,参数情况如下:
pandas.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
这里不再赘述了,看以下一些例子:
In [15]: d = { 'one': pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
...: 'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
...:
In [16]: d
Out[16]:
{'one': a 1.0
b 2.0
c 3.0
dtype: float64, 'two': a 1.0
b 2.0
c 3.0
d 4.0
dtype: float64}
In [17]: df = pd.DataFrame(d)
In [18]: df
Out[18]:
one two
a 1.0 1.0
b 2.0 2.0
c 3.0 3.0
d NaN 4.0
In [19]: pd.DataFrame(d, index=['d', 'b', 'a'])
Out[19]:
one two
d NaN 4.0
b 2.0 2.0
a 1.0 1.0
In [20]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
Out[20]:
two three
d 4.0 NaN
b 2.0 NaN
a 1.0 NaN
In [21]: df.index
Out[21]: Index(['a', 'b', 'c', 'd'], dtype='object')
In [22]: df.columns
Out[22]: Index(['one', 'two'], dtype='object')
注:在Pandas中,缺失值一般用NaN表示。
会创建Series和Pandas对象只是学习Pandas的第一步,其实Pandas更加强大的地方在于它在这两个核心数据结构之上提供了非常丰富的函数和方法,让我们可以更专注于数据分析本身。本文的重点不是介绍Pandas,所以Pandas的介绍到此为止,有兴趣的可以看起官方文档:http://pandas.pydata.org/pandas-docs/stable/index.html。里面有一个10分钟的入门教程,对于只想快速了解一下的同学是个非常不错的选择。
下面我们言归正传,看一下如何利用Pandas提供的各种工具来探索我们的数据。
数据说明:本次示例所用的数据来自于https://archive.ics.uci.edu/ml/datasets/bank+marketing,是葡萄牙银行做的一次电话调查,旨在判断用户对于行方定期存储产品的认购情况。数据包含了很多列,有些列的值是标量型的,有些是数值型的。本文的重点在于如何利用Pandas工具去探索数据(分布)情况,所以列的含义不是那么重要,这里就不解释了,有兴趣的可以去上面给出的链接处查看,有详细的说明。
导入相关的包并读入数据:
In [1]: import numpy as np
In [2]: import pandas as pd
In [3]: import matplotlib.pyplot as plt
In [4]: df = pd.read_csv('SampleData/banking.csv')
1,查看数据基本信息。
# head默认显示5条数据,可以指定显示几条
In [5]: df.head()
Out[5]:
age job marital education default housing loan \
0 44 blue-collar married basic.4y unknown yes no
1 53 technician married unknown no no no
2 28 management single university.degree no yes no
3 39 services married high.school no no no
4 55 retired married basic.4y no yes no
contact month day_of_week ... campaign pdays previous poutcome \
0 cellular aug thu ... 1 999 0 nonexistent
1 cellular nov fri ... 1 999 0 nonexistent
2 cellular jun thu ... 3 6 2 success
3 cellular apr fri ... 2 999 0 nonexistent
4 cellular aug fri ... 1 3 1 success
emp_var_rate cons_price_idx cons_conf_idx euribor3m nr_employed y
0 1.4 93.444 -36.1 4.963 5228.1 0
1 -0.1 93.200 -42.0 4.021 5195.8 0
2 -1.7 94.055 -39.8 0.729 4991.6 1
3 -1.8 93.075 -47.1 1.405 5099.1 0
4 -2.9 92.201 -31.4 0.869 5076.2 1
[5 rows x 21 columns]
# 查看数据维度
In [6]: df.shape
Out[6]: (41188, 21)
# 查看数据类型
In [7]: df.dtypes
Out[7]:
age int64
job object
marital object
education object
default object
housing object
loan object
contact object
month object
day_of_week object
duration int64
campaign int64
pdays int64
previous int64
poutcome object
emp_var_rate float64
cons_price_idx float64
cons_conf_idx float64
euribor3m float64
nr_employed float64
y int64
dtype: object
通过查看基本信息,我们可以查看到一些示例数据,以及数据总条数、维度数,各个维度的类型等,这些都是我们探索数据的第一步。
2,通过Pandas的describe
方法查看一些汇总信息,探索各个维度值的分布情况:
In [11]: df.describe()
Out[11]:
age duration campaign pdays previous \
count 41188.00000 41188.000000 41188.000000 41188.000000 41188.000000
mean 40.02406 258.285010 2.567593 962.475454 0.172963
std 10.42125 259.279249 2.770014 186.910907 0.494901
min 17.00000 0.000000 1.000000 0.000000 0.000000
25% 32.00000 102.000000 1.000000 999.000000 0.000000
50% 38.00000 180.000000 2.000000 999.000000 0.000000
75% 47.00000 319.000000 3.000000 999.000000 0.000000
max 98.00000 4918.000000 56.000000 999.000000 7.000000
emp_var_rate cons_price_idx cons_conf_idx euribor3m \
count 41188.000000 41188.000000 41188.000000 41188.000000
mean 0.081886 93.575664 -40.502600 3.621291
std 1.570960 0.578840 4.628198 1.734447
min -3.400000 92.201000 -50.800000 0.634000
25% -1.800000 93.075000 -42.700000 1.344000
50% 1.100000 93.749000 -41.800000 4.857000
75% 1.400000 93.994000 -36.400000 4.961000
max 1.400000 94.767000 -26.900000 5.045000
nr_employed y
count 41188.000000 41188.000000
mean 5167.035911 0.112654
std 72.251528 0.316173
min 4963.600000 0.000000
25% 5099.100000 0.000000
50% 5191.000000 0.000000
75% 5228.100000 0.000000
max 5228.100000 1.000000
可以看到该方法默认只计算了数值型维度的5个方面的信息:
当然,对于数值型数据describe
方法会统计上面5个方面的信息,对于标称型数据则统计另外4个方面的信息:
In [13]: df.describe(exclude=[np.number])
Out[13]:
job marital education default housing loan contact \
count 41188 41188 41188 41188 41188 41188 41188
unique 12 4 8 3 3 3 2
top admin. married university.degree no yes no cellular
freq 10422 24928 12168 32588 21576 33950 26144
month day_of_week poutcome
count 41188 41188 41188
unique 10 5 3
top may thu nonexistent
freq 13769 8623 35563
这4方面的信息包括:
对于Timestamp类型还会有first和last两个信息。
3,通过groupby
查看各个标称型维度值的分布情况。describe方法对于探索数值型数据的分布非常有用,但对于标称型数据虽然也有统计,但还不够。往往我们更多的使用groupby
方法,该方法与SQL中的groupby类似,这里举几个例子:
In [14]: df.groupby('education').size()
Out[14]:
education
basic.4y 4176
basic.6y 2292
basic.9y 6045
high.school 9515
illiterate 18
professional.course 5243
university.degree 12168
unknown 1731
dtype: int64
In [15]: df.groupby('y').size()
Out[15]:
y
0 36548
1 4640
dtype: int64
4,有很多算法要求所选取的维度之间要没有相关性,所以探索维度之间的相关性也非常重要。Pandas提供了corr
方法可以计算相关系数(默认计算皮尔逊相关系数):
In [16]: df.corr()
Out[16]:
age duration campaign pdays previous \
age 1.000000 -0.000866 0.004594 -0.034369 0.024365
duration -0.000866 1.000000 -0.071699 -0.047577 0.020640
campaign 0.004594 -0.071699 1.000000 0.052584 -0.079141
pdays -0.034369 -0.047577 0.052584 1.000000 -0.587514
previous 0.024365 0.020640 -0.079141 -0.587514 1.000000
emp_var_rate -0.000371 -0.027968 0.150754 0.271004 -0.420489
cons_price_idx 0.000857 0.005312 0.127836 0.078889 -0.203130
cons_conf_idx 0.129372 -0.008173 -0.013733 -0.091342 -0.050936
euribor3m 0.010767 -0.032897 0.135133 0.296899 -0.454494
nr_employed -0.017725 -0.044703 0.144095 0.372605 -0.501333
y 0.030399 0.405274 -0.066357 -0.324914 0.230181
emp_var_rate cons_price_idx cons_conf_idx euribor3m \
age -0.000371 0.000857 0.129372 0.010767
duration -0.027968 0.005312 -0.008173 -0.032897
campaign 0.150754 0.127836 -0.013733 0.135133
pdays 0.271004 0.078889 -0.091342 0.296899
previous -0.420489 -0.203130 -0.050936 -0.454494
emp_var_rate 1.000000 0.775334 0.196041 0.972245
cons_price_idx 0.775334 1.000000 0.058986 0.688230
cons_conf_idx 0.196041 0.058986 1.000000 0.277686
euribor3m 0.972245 0.688230 0.277686 1.000000
nr_employed 0.906970 0.522034 0.100513 0.945154
y -0.298334 -0.136211 0.054878 -0.307771
nr_employed y
age -0.017725 0.030399
duration -0.044703 0.405274
campaign 0.144095 -0.066357
pdays 0.372605 -0.324914
previous -0.501333 0.230181
emp_var_rate 0.906970 -0.298334
cons_price_idx 0.522034 -0.136211
cons_conf_idx 0.100513 0.054878
euribor3m 0.945154 -0.307771
nr_employed 1.000000 -0.354678
y -0.354678 1.000000
皮尔逊相关系数取值范围为[-1, 1],-1表示(线性)负相关,0表示(线性)无关,1表示(线性)正相关。通过这个(对角)矩阵,我们可以很容易的看出各个属性间的相关性。
5,pandas还提供了skew
来计算偏度(skew):衡量实数随机变量概率分布的不对称性。偏度的值可以为正,可以为负或者甚至是无法定义。在数量上,偏度为负(左偏态或负偏态,Negative Skew)就意味着在概率密度函数左侧的尾部比右侧的长,绝大多数的值(包括中位数在内)位于平均值的右侧。偏度为正(右偏态或正偏态,Positive Skew)就意味着在概率密度函数右侧的尾部比左侧的长,绝大多数的值(但不一定包括中位数)位于平均值的左侧。如图:
偏度为零就表示数值相对均匀地分布在平均值的两侧,但不一定意味着其为对称分布。如果分布对称,那么平均值=中位数,偏度为零(此外,如果分布为单峰分布,那么平均值=中位数=众数)。
In [17]: df.skew()
Out[17]:
age 0.784697
duration 3.263141
campaign 4.762507
pdays -4.922190
previous 3.832042
emp_var_rate -0.724096
cons_price_idx -0.230888
cons_conf_idx 0.303180
euribor3m -0.709188
nr_employed -1.044262
y 2.450330
dtype: float64
统计信息虽然非常精确,但看上去并不是非常直观,我们可以通过一些可视化的手段来非常直观的探索数据分布。
1,直方图(histogram):
In [20]: %matplotlib
Using matplotlib backend: MacOSX
In [21]: df.hist(figsize=(12, 8))
2,密度图(density plot):
In [22]: df.plot(kind='density', subplots=True, figsize=(12,8), layout=(3,4), sharex=False)
3,箱型图(boxplots):
In [23]: df.plot(kind='box', subplots=True, figsize=(12,8), layout=(3,4), sharex=False, sharey=False)
箱型图的含义参见:箱型图介绍。
4,相关系数矩阵图:
corr = df.corr()
figure = plt.figure(figsize=(12,8))
ax = figure.add_subplot(111)
cax = ax.matshow(corr, vmin=-1, vmax=1)
figure.colorbar(cax)
plt.show() # 0~10,依次对应age~y
5,通过散点矩阵图(scatter matrix)查看各维度相关性:
from pandas.plotting import scatter_matrix
scatter_matrix(df, figsize=(18, 12))
关于scatter matrix需要解释一下,和上面的相关系数矩阵图类似,该图也描述了各维度间的相关性。而对角线上是各个维度自己与自己的相关性,显然都是完全相关的,也就是一条直线(皮尔逊相关系数为1),这没什么用。所以Pandas就把对角线上面的改为展示维度的密度图了。这里再附上皮尔逊相关系数的值与其图形的关系(图片来自皮尔逊相关系数维基百科):
以及一个比较泛(不是非常的严格和通用)的判断相关性强弱的标准:
相关性 | 负 | 正 |
---|---|---|
无 | -0.09~0.0 | 0.0~0.09 |
弱 | -0.3~-0.1 | 0.1~0.3 |
中 | -0.5~-0.3 | 0.3~0.5 |
强 | -1.0~-0.5 | 0.5~1.0 |
可视化可以帮助我们“定性的”了解数据,统计信息则帮助我们“定量的”了解数据,二者结合可以使我们更加了解自己的数据,从而选择下一步的数据处理流程。除了本文已经介绍的之外,Pandas还有非常非常多的工具帮助我们分析数据,可以查看其文档慢慢积累。
本文源码见这里。
References: