数据分析三剑客
数据分析三剑客:
Numpy,Pandas,Matplotlib
NumPy
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
一、创建ndarray
1. 使用np.array()创建
一维数据创建
import numpy as np arr = np.array([1,2,3,4,5]) arr #结果 array([1, 2, 3, 4, 5])
二维数据创建
import numpy as np arr = np.array([[1,2,3],[4,5,6]]) arr #结果 array([[1, 2, 3], [4, 5, 6]])
元素类型相同
arr = np.array([[1,2,3],[4,5.123,6]]) arr # 结果 array([[1. , 2. , 3. ], [4. , 5.123, 6. ]])
注意:
numpy默认ndarray的所有元素的类型是相同的 如果传进来的列表中包含不同的类型,则统一为同一类型,优先级:str>float>int 使用matplotlib.pyplot获取一个numpy数组,数据来源于一张图片
图片
import matplotlib.pyplot as plt img_arr = plt.imread('./cat.jpg') img_arr # 三维数组 要先加载数组 plt.imshow(img_arr) #将三维数组转换图片
2. 使用np的routines函数创建
1. np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) 等差数列
import numpy as np np.linspace(0,100,num=10)
2. np.arange([start, ]stop, [step, ]dtype=None)
np.arange(0,100,2)
3. np.random.randint(low, high=None, size=None, dtype='l')
时间种子(随机因子):无时无刻都在变化的值(系统时间)
固定随机因子就可以固定随机函数的随机性
np.random.seed(90) # 固定 np.random.randint(0,100,size=(3,5)) # 随机
4. np.random.random(size=None)
生成0到1的随机数,左闭右开 np.random.seed(3)
二、ndarray的属性
4个必记参数: ndim:维度 shape:形状(各维度的长度) size:总长度
dtype:元素类型
type(img_arr) img_arr.shape # 形状 arr.shape arr.size arr.dtype arr.ndim
三、ndarray的基本操作
1. 索引
一维与列表完全一致 多维时同理
arr = np.random.randint(0,100,size=(5,8)) arr # 根据索引修改数据 arr[0] arr[[0,1]] arr[1,3] arr[1,[2,3,4]]
2. 切片
一维与列表完全一致 多维时同理
arr = np.random.randint(0,100,size=(5,8)) arr #获取二维数组前两行 arr[0:2] #获取二维数组前两列 arr[:,0:2] #arr[hang,lie] #获取二维数组前两行和前两列数据 arr[0:2,0:2]
将数据反转,例如[1,2,3]---->[3,2,1]
::进行切片
#将数组的行倒序 arr[::-1,:] #列倒序 arr[:,::-1] #全部倒序 arr[::-1,::-1] #将图片进行全倒置操作 plt.imshow(img_arr) plt.imshow(img_arr[:,::-1,:]) plt.imshow(img_arr[:,::-1,:]) plt.imshow(img_arr[::-1,::-1,::-1]) plt.imshow(img_arr[100:360:,150:580,:])
3. 变形
使用arr.reshape()函数,注意参数是一个tuple!
基本使用
1.将一维数组变形成多维数组
arr_1.reshape((10,4))
arr_1.reshape((5,-1))
2.将多维数组变形成一维数组 (要于二维数量相同)
arr_1 = arr.reshape((40,))
arr_1
4. 级联
np.concatenate()
级联需要注意的点:
- 级联的参数是列表:一定要加中括号或小括号
- 维度必须相同
- 形状相符:在维度保持一致的前提下,如果进行横向(axis=1)级联,必须保证进行级联的数组行数保持一致。如果进行纵向(axis=0)级联,必须保证进行级联的数组列数保持一致。
- 可通过axis参数改变级联的方向
1.一维,二维,多维数组的级联,实际操作中级联多为二维数组
np.concatenate((arr,arr),axis=1) # arr数组 axis轴向
2.合并两张照片
arr_3 = np.concatenate((img_arr,img_arr,img_arr),axis=1) arr_9 = np.concatenate((arr_3,arr_3,arr_3),axis=0) plt.imshow(arr_9)
四、ndarray的聚合操作
1. 求和np.sum
arr.sum(axis=1) # 列的和
2. 最大最小值:np.max/ np.min
同理
3.平均值:np.mean()
arr.mean(axis=0)
五、其他聚合操作
Function Name NaN-safe Version Description np.sum np.nansum Compute sum of elements np.prod np.nanprod Compute product of elements np.mean np.nanmean Compute mean of elements np.std np.nanstd Compute standard deviation np.var np.nanvar Compute variance np.min np.nanmin Find minimum value np.max np.nanmax Find maximum value np.argmin np.nanargmin Find index of minimum value np.argmax np.nanargmax Find index of maximum value np.median np.nanmedian Compute median of elements np.percentile np.nanpercentile Compute rank-based statistics of elements np.any N/A Evaluate whether any elements are true np.all N/A Evaluate whether all elements are true np.power 幂运算
六、ndarray的排序
1. 快速排序
np.sort()与ndarray.sort()都可以,但有区别:
- np.sort()不改变输入
- ndarray.sort()本地处理,不占用空间,但改变输入
np.sort(arr,axis=0)
arr.sort(axis=1)
Pandas的数据结构
导入pandas:
三剑客
import pandas as pd from pandas import Series,DataFrame import numpy as np
Series
1、Series
Series是一种类似与一维数组的对象,由下面两个部分组成:
- values:一组数据(ndarray类型)
- index:相关的数据索引标签
1)Series的创建
两种创建方式:
(1) 由列表或numpy数组创建默认索引为0到N-1的整数型索引
#使用列表创建Series Series(data=[1,2,3])
还可以通过设置index参数指定索引
s = Series(data=[1,2,3],index=['a','b','c'])
s[0]
s['a']
s.a
# 1
2)Series的索引和切片
可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的是一个Series类型)。
(1) 显式索引:
- 使用index中的元素作为索引值
- 使用s.loc[](推荐):注意,loc中括号中放置的一定是显示索引
注意,此时是闭区间
s[0:2]
3)Series的基本概念
可以使用s.head(),tail()分别查看前n个和后n个值
s = Series(data=[1,1,2,3,4,5,5,6,7,8])
s.head(2)
对Series元素进行去重
s.unique()
当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况
- 使得两个Series进行相加
s1 = Series([1,2,3],index=['a','b','c']) s2 = Series([1,2,3],index=['a','d','c']) s = s1 + s2 s
可以使用pd.isnull(),pd.notnull(),或s.isnull(),notnull()函数检测缺失数据
s.isnull()
s.notnull()
#将Series中的空值直接进行了清洗
s[s.notnull()]
(3) Series之间的运算
- 在运算中自动对齐不同索引的数据
- 如果索引不对应,则补NaN
DataFrame
DataFrame是一个【表格型】的数据结构。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。
- 行索引:index
- 列索引:columns
- 值:values
1)DataFrame的创建
最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。
此外,DataFrame会自动加上每一行的索引。
使用字典创建的DataFrame后,则columns参数将不可被使用。
同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。
- 使用ndarray创建DataFrame
df = DataFrame(data=np.random.randint(0,100,size=(3,4)),index=['a','b','c'],columns=['A','B','C','D'])
DataFrame属性:values、columns、index、shape
df.values # 值 df.columns # 列索引 df.index # 行索引 df.shape # 形态
使用ndarray创建DataFrame:创建一个表格用于展示张三,李四,王五的java,python的成绩
dic = { 'zhangsan':[99,99,99,99], 'lisi':[0,0,0,0] } df = DataFrame(data=dic,index=['语文','数学','英语','理综'])
2)DataFrame的索引
(1) 对列进行索引 - 通过类似字典的方式 df['q'] - 通过属性的方式 df.q 可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。
df['lisi'] #列索引 df[['zhangsan','lisi']]
(2) 对行进行索引
- 使用.loc[]加index来进行行索引
- 使用.iloc[]加整数来进行行索引
同样返回一个Series,index为原来的columns。
df.loc['语文'] df.iloc[0] # 行 df.iloc[[0,1]] # 列
(3) 对元素索引的方法
- 使用列索引
- 使用行索引(iloc[3,1] or loc['C','q']) 行索引在前,列索引在后
df.iloc[2,1] df.loc['英语','zhangsan'] df.iloc[[1,2],1]
切片:
【注意】 直接用中括号时:
- 索引表示的是列索引
- 切片表示的是行切片
在loc和iloc中使用切片(切列) : df.loc['B':'C','丙':'丁']
df.iloc[:,0:1]
- 索引
- df['col']:列索引,取出指定的列
- df[[col1,col2]]:取出多列
- df.iloc[1]:取指定的1行
- df.loc['语文']:取指定的行
- df.iloc[hang,lie]:取元素
- 切片:
- df[行切片]:切行
- df.iloc[hang,lie]:切列
3)DataFrame的运算
(1) DataFrame之间的运算
同Series一样:
- 在运算中自动对齐不同索引的数据
- 如果索引不对应,则补NaN
qizhong = df mean_score = (qizhong + qimo)/2 qizhong.iloc[1,1] = 0 qizhong['lisi'] += 100 qizhong += 10
股票的历史行情例子
使用tushare包获取某股票的历史行情数据
- pip install tushare
import tushare as ts import pandas as pd
maotai = ts.get_k_data(code='600519',start='1900-01-01')
maotai.head() # 查看数据
#存储本地
maotai.to_csv('./maotai.csv')
#从本地读取数据
#index_col将哪一列作为原数据的行索引
#将date的类型转成时间类型然后将其作为原数据的行索引
df = pd.read_csv('./maotai.csv',index_col='date',parse_dates=['date'])
df.drop(labels='Unnamed: 0',axis=1,inplace=True) # drop移除
df.head()
输出该股票所有收盘比开盘上涨3%以上的日期。
#(收盘-开盘)/开盘 > 0.03 (df['close'] - df['open']) / df['open'] > 0.03 #将True对应的行数据取出 df.loc[(df['close'] - df['open']) / df['open'] > 0.03] #取行索引 df.loc[(df['close'] - df['open']) / df['open'] > 0.03].index
输出该股票所有开盘比前日收盘跌幅超过2%的日期。
#(开盘-前日收盘)/前日收盘 < -0.02 (df['open'] - df['close'].shift(1)) / df['close'].shift(1) < -0.02 df.loc[(df['open'] - df['close'].shift(1)) / df['close'].shift(1) < -0.02] df.loc[(df['open'] - df['close'].shift(1)) / df['close'].shift(1) < -0.02].index
假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?
df_2010 = df['2010':'2019'] df_2010
买入股票花费的钱数
df_monthly = df_2010.resample('M').first() df_monthly
昨天的收盘价
last_price = df_2010['close'][-1] recv_monry = df_yearly['open'].sum()*1200 + last_price*1000 recv_monry - cost_money
处理丢失数据
有两种丢失数据:
- None
- np.nan(NaN)
import numpy as np import pandas from pandas import DataFrame
1. None
None是Python自带的,其类型为python object。因此,None不能参与到任何计算中。
#查看None的数据类型 type(None) # NoneType
2. np.nan(NaN)
np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。
#查看np.nan的数据类型 type(np.nan) # float
3. pandas中的None与NaN
1) pandas中None与np.nan都视作np.nan
创建DataFrame
df = DataFrame(data=np.random.randint(0,100,size=(10,8)))
df
#将某些数组元素赋值为nan
df.iloc[1,4] = None
df.iloc[3,6] = None
df.iloc[7,7] = None
df.iloc[3,1] = None
df.iloc[5,5] = np.nan
df
2) pandas处理空值操作
(1)判断函数
isnull()
notnull()
- isnull()->any
- notnull()->all
df.isnull()
df.notnull()
df.isnull().any(axis=1)
df.notnull().all(axis=1)
df.loc[~df.isnull().any(axis=1)]
(2)过滤df中的空值(只保留没有空值的行)
df.dropna() 可以选择过滤的是行还是列(默认为行):axis中0表示行,1表示的列
df.dropna(axis=0)
(3) 填充函数 Series/DataFrame
fillna()
:value和method参数
df_test = df.fillna(method='bfill',axis=1).fillna(method='ffill',axis=1) df_test
测试df_test中的哪些列中还有空值
#测试df_test中的哪些列中还有空值 df_test.isnull().any(axis=0)
pandas的拼接操作
pandas的拼接分为两种:
- 级联:pd.concat, pd.append
- 合并:pd.merge, pd.join
import pandas as pd import numpy as np from pandas import DataFrame,Series
1. 使用pd.concat()级联
pandas使用pd.concat函数,与np.concatenate函数类似,只是多了一些参数:
objs
axis=0
keys
join='outer' / 'inner':表示的是级联的方式,outer会将所有的项进行级联(忽略匹配和不匹配),而inner只会将匹配的项级联到一起,不匹配的不级联
ignore_index=False
1)匹配级联
df1 = DataFrame(data=np.random.randint(0,100,size=(3,4))) df2 = DataFrame(data=np.random.randint(0,100,size=(3,4))) pd.concat((df1,df2),axis=0) # 竖着排序
2) 不匹配级联
不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致
有2种连接方式:
外连接:补NaN(默认模式)
内连接:只连接匹配的项
df1 = DataFrame(data=np.random.randint(0,100,size=(3,4))) df2 = DataFrame(data=np.random.randint(0,100,size=(3,3))) pd.concat((df1,df2),axis=0) pd.concat((df1,df2),axis=0,join='inner') # inner只会将匹配的项级联到一起
2. 使用pd.merge()合并
merge与concat的区别在于,merge需要依据某一共同的列来进行合并
使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。
注意每一列元素的顺序不要求一致
参数:
- how:outer取并集 inner取交集
- on:当有多列相同的时候,可以使用on来指定使用那一列进行合并,on的值为一个列表
1) 一对一合并
df1 = DataFrame({'employee':['Bob','Jake','Lisa'], 'group':['Accounting','Engineering','Engineering'], }) df2 = DataFrame({'employee':['Lisa','Bob','Jake'], 'hire_date':[2004,2008,2012], }) pd.merge(df1,df2) # 合并
2) 多对一合并
df3 = DataFrame({ 'employee':['Lisa','Jake'], 'group':['Accounting','Engineering'], 'hire_date':[2004,2016]}) df4 = DataFrame({'group':['Accounting','Engineering','Engineering'], 'supervisor':['Carly','Guido','Steve'] }) pd.merge(df3,df4) # 合并
3) 多对多合并
df1 = DataFrame({'employee':['Bob','Jake','Lisa'], 'group':['Accounting','Engineering','Engineering']}) df5 = DataFrame({'group':['Engineering','Engineering','HR'], 'supervisor':['Carly','Guido','Steve'] }) pd.merge(df1,df5,how='right') # how表示连接方式
4) key的规范化
当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名
df1 = DataFrame({'employee':['Jack',"Summer","Steve"], 'group':['Accounting','Finance','Marketing']}) df2 = DataFrame({'employee':['Jack','Bob',"Jake"], 'hire_date':[2003,2009,2012], 'group':['Accounting','sell','ceo']}) pd.merge(df1,df2,on='employee') #
当两张表没有可进行连接的列时,可使用left_on和right_on手动指定merge中左右两边的哪一列列作为连接的列
df1 = DataFrame({'employee':['Bobs','Linda','Bill'], 'group':['Accounting','Product','Marketing'], 'hire_date':[1998,2017,2018]}) df5 = DataFrame({'name':['Lisa','Bobs','Bill'], 'hire_dates':[1998,2016,2007]}) pd.merge(df1,df5,left_on='employee',right_on='name',how='outer') # how是表示连接方式
5) 内合并与外合并:out取并集 inner取交集
# 内合并:只保留两者都有的key(默认模式 df6 = DataFrame({'name':['Peter','Paul','Mary'], 'food':['fish','beans','bread']} ) df7 = DataFrame({'name':['Mary','Joseph'], 'drink':['wine','beer']}) # 外合并 how='outer':补NaN df6 = DataFrame({'name':['Peter','Paul','Mary'], 'food':['fish','beans','bread']} ) df7 = DataFrame({'name':['Mary','Joseph'], 'drink':['wine','beer']})
人口分析
需求:
- 导入文件,查看原始数据
- 将人口数据和各州简称数据进行合并
- 将合并的数据中重复的abbreviation列进行删除
- 查看存在缺失数据的列
- 找到有哪些state/region使得state的值为NaN,进行去重操作
- 为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN
- 合并各州面积数据areas
- 我们会发现area(sq.mi)这一列有缺失数据,找出是哪些行
- 去除含有缺失数据的行
- 找出2010年的全民人口数据
- 计算各州的人口密度
- 排序,并找出人口密度最高的五个州 df.sort_values()
import numpy as np from pandas import DataFrame,Series import pandas as pd
导入文件,查看原始数据
abb = pd.read_csv('./data/state-abbrevs.csv') abb.head(2) pop = pd.read_csv('./data/state-population.csv') pop.head(2) area = pd.read_csv('./data/state-areas.csv') area.head(2)
将人口数据和各州简称数据进行合并
#将人口数据和各州简称数据进行合并 abb_pop = pd.merge(abb,pop,left_on='abbreviation',right_on='state/region',how='outer') abb_pop.head(2)
将合并的数据中重复的abbreviation列进行删除
#将合并的数据中重复的abbreviation列进行删除 abb_pop.drop(labels='abbreviation',axis=1,inplace=True) abb_pop.head(2)
查看存在缺失数据的列
#查看存在缺失数据的列 abb_pop.isnull().any(axis=0)
找到有哪些state/region使得state的值为NaN,进行去重操作
#找到有哪些state/region使得state的值为NaN,进行去重操作 #1.state列中哪些值为空 abb_pop['state'].isnull()
为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN
#为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN #1.先将USA对应的state列中的空值定位到 abb_pop['state/region'] == 'USA' #为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN #1.先将USA对应的state列中的空值定位到 abb_pop['state/region'] == 'USA' #3.获取符合要求行数据的行索引 indexs = abb_pop.loc[abb_pop['state/region'] == 'USA'].index #4.将indexs这些行中的state列的值批量赋值成united states abb_pop.loc[indexs,'state'] = 'United Status' #将PR对应的state列中的空批量赋值成 PUERTO RICO abb_pop['state/region'] == 'PR' abb_pop.loc[abb_pop['state/region'] == 'PR'] indexs = abb_pop.loc[abb_pop['state/region'] == 'PR'].index abb_pop.loc[indexs,'state'] = 'PUERTO RICO'
合并各州面积数据areas
#合并各州面积数据areas abb_pop_area = pd.merge(abb_pop,area,how='outer') abb_pop_area.head(3)
我们会发现area(sq.mi)这一列有缺失数据,找出是哪些行
#我们会发现area(sq.mi)这一列有缺失数据,找出是哪些行 abb_pop_area['area (sq. mi)'].isnull() #将空值对应的行数据取出 indexs = abb_pop_area.loc[abb_pop_area['area (sq. mi)'].isnull()].index indexs
去除含有缺失数据的行
#去除含有缺失数据的行 abb_pop_area.drop(labels=indexs,axis=0,inplace=True)
找出2010年的全民人口数据
#找出2010年的全民人口数据 abb_pop_area.query('year == 2010 & ages == "total"')
计算各州的人口密度
#计算各州的人口密度 abb_pop_area['midu'] = abb_pop_area['population'] / abb_pop_area['area (sq. mi)'] abb_pop_area.head(2)
排序,并找出人口密度最高的五个州 df.sort_values()
abb_pop_area.sort_values(by='midu',axis=0,ascending=False).head(5)
数据竞赛平台
pandas数据处理
- 检测过滤缺失值
- dropna #删除
- fillna #填充
- 检测过滤重复值
- drop_duplicated(keep)
- 检测过滤异常值
- 得到鉴定异常值的条件
- 将异常值对应的行删除
1、删除重复元素
使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True
- keep参数:指定保留哪一重复的行数据
- 创建具有重复元素行的DataFrame
import numpy as np import pandas as pd from pandas import DataFrame
#创建一个df df = DataFrame(data=np.random.randint(0,100,size=(12,7))) #手动将df的某几行设置成相同的内容 df.iloc[1] = [6,6,6,6,6,6,6] df.iloc[8] = [6,6,6,6,6,6,6] df.iloc[5] = [6,6,6,6,6,6,6]
使用drop_duplicates()函数删除重复的行
- drop_duplicates(keep='first/last'/False)
df.drop_duplicates(keep='last')
2. 映射
1) replace()函数:替换元素
DataFrame替换操作
- 单值替换
- 普通替换: 替换所有符合要求的元素:to_replace=15,value='e'
- 按列指定单值替换: to_replace={列标签:替换值} value='value'
- 多值替换
- 列表替换: to_replace=[] value=[]
- 字典替换(推荐) to_replace={to_replace:value,to_replace:value}
注意:DataFrame中,无法使用method和limit参数
df.replace(to_replace=6,value='six')
df.replace(to_replace={6:'six'})
df.replace(to_replace={5:6},value='six') # 第5列第6行
2) map()函数:新建一列 , map函数并不是df的方法,而是series的方法
- map()可以映射新一列数据
- map()中可以使用lambd表达式
-
map()中可以使用方法,可以是自定义的方法
eg:map({to_replace:value})
- 注意 map()中不能使用sum之类的函数,for循环
- 新增一列:给df中,添加一列,该列的值为中文名对应的英文名
dic = { 'name':['张三','周杰伦','张三'], 'salary':[20000,10000,20000] } df = DataFrame(data=dic) #映射关系表 dic = { '张三':'tom', '周杰伦':'jay' } df['e_name'] = df['name'].map(dic) df
map当做一种运算工具,至于执行何种运算,是由map函数的参数决定的(参数:lambda,函数)
使用自定义函数
def after_sal(s): return s - (s-3000)*0.5 #超过3000部分的钱缴纳50%的税 df['after_sal'] = df['salary'].map(after_sal) df #apply效率高于map df['after_sal'] = df['salary'].apply(after_sal) df
使用lambda表达式
注意:并不是任何形式的函数都可以作为map的参数。只有当一个函数具有一个参数且有返回值,那么该函数才可以作为map的参数。
3. 使用聚合操作对数据异常值检测和过滤
使用df.std()函数可以求得DataFrame对象每一列的标准差
- 创建一个1000行3列的df 范围(0-1),求其每一列的标准差
df = DataFrame(data=np.random.random(size=(1000,3)),columns=['A','B','C']) # 对df应用筛选条件,去除标准差太大的数据:假设过滤条件为 C列数据大于两倍的C列标准差 twice_std = df['C'].std() * 2 twice_std ~(df['C'] > twice_std) df.loc[~(df['C'] > twice_std)]
4. 排序
使用.take()函数排序
- take()函数接受一个索引列表,用数字表示,使得df根据列表中索引的顺序进行排序
- eg:df.take([1,3,4,2,5])
可以借助np.random.permutation()函数随机排序
np.random.permutation(x)可以生成x个从0-(x-1)的随机数列
np.random.permutation(1000) df.take(indices=np.random.permutation(1000),axis=0).take(indices=np.random.permutation(3),axis=1) df.take(indices=np.random.permutation(1000),axis=0).take(indices=np.random.permutation(3),axis=1)[0:5]
随机抽样
当DataFrame规模足够大时,直接使用np.random.permutation(x)函数,就配合take()函数实现随机抽样
5. 数据分类处理【重点】
数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。
数据分类处理:
- 分组:先把数据分为几组
- 用函数处理:为不同组的数据应用不同的函数以转换数据
- 合并:把不同组得到的结果合并起来
数据分类处理的核心:
- groupby()函数
- groups属性查看分组情况
- eg: df.groupby(by='item').groups
分组
to_dict 转字典
mean 求均值
df = DataFrame({'item':['Apple','Banana','Orange','Banana','Orange','Apple'], 'price':[4,3,3,2.5,4,2], 'color':['red','yellow','yellow','green','green','green'], 'weight':[12,20,50,30,20,44]})
# 使用groupby实现分组 df.groupby(by='item',axis=0) # 使用groups查看分组情况 #该函数可以进行数据的分组,但是不显示分组情况 # 分组后的聚合操作:分组后的成员中可以被进行运算的值会进行运算,不能被运算的值不进行运算 df.groupby(by='item',axis=0).groups #给df创建一个新列,内容为各个水果的平均价格 df.groupby(by='item',axis=0).mean()['price'] #错误版 #给df创建一个新列,内容为各个水果的平均价格 df.groupby(by='item',axis=0).mean()['price'] #映射关系表 dic = mean_price_series.to_dict() df['mean_price'] = df['item'].map(dic) # 汇总:将各种颜色水果的平均价格和df进行汇总 df['color_mean_price'] = df['color'].map(df.groupby(by='color')['price'].mean().to_dict())
6. 高级数据聚合
使用groupby分组后,也可以使用transform和apply提供自定义函数实现更多的运算
- df.groupby('item')['price'].sum() <==> df.groupby('item')['price'].apply(sum)
- transform和apply都会进行运算,在transform或者apply中传入函数即可
- transform和apply也可以传入一个lambda表达式
df.groupby(by='item')['price'].mean()
def my_mean(s):
sum = 0
for i in s:
sum += i
return sum/len(s)
#使用apply函数求出水果的平均价格
df.groupby(by='item')['price'].apply(my_mean)
#使用transform函数求出水果的平均价格
df.groupby(by='item')['price'].transform(my_mean)
美国2012年总统候选人政治献金数据分析
导入包
import numpy as np import pandas as pd from pandas import Series,DataFrame
map映射,unique唯一,value_counts出现次数,sum总和,max最大,query查找(条件=‘’)
months = {'JAN' : 1, 'FEB' : 2, 'MAR' : 3, 'APR' : 4, 'MAY' : 5, 'JUN' : 6, 'JUL' : 7, 'AUG' : 8, 'SEP' : 9, 'OCT': 10, 'NOV': 11, 'DEC' : 12} of_interest = ['Obama, Barack', 'Romney, Mitt', 'Santorum, Rick', 'Paul, Ron', 'Gingrich, Newt'] parties = { 'Bachmann, Michelle': 'Republican', 'Romney, Mitt': 'Republican', 'Obama, Barack': 'Democrat', "Roemer, Charles E. 'Buddy' III": 'Reform', 'Pawlenty, Timothy': 'Republican', 'Johnson, Gary Earl': 'Libertarian', 'Paul, Ron': 'Republican', 'Santorum, Rick': 'Republican', 'Cain, Herman': 'Republican', 'Gingrich, Newt': 'Republican', 'McCotter, Thaddeus G': 'Republican', 'Huntsman, Jon': 'Republican', 'Perry, Rick': 'Republican' }
df = pd.read_csv('./data/usa_election.txt') df.head() #新建一列各个候选人所在党派party df['party'] = df['cand_nm'].map(parties) df.head() #party这一列中有哪些元素 df['party'].unique() #统计party列中各个元素出现次数 df['party'].value_counts() #查看各个党派收到的政治献金总数contb_receipt_amt df.groupby(by='party')['contb_receipt_amt'].sum() #查看每天各个党派收到的政治献金总数contb_receipt_amt df.groupby(by=['contb_receipt_dt','party'])['contb_receipt_amt'].sum() #将表中日期格式转换为'yyyy-mm-dd' day-m-y def transformDate(d): day,month,year = d.split('-') month = months[month] return '20'+year+'-'+str(month)+'-'+day df['contb_receipt_dt'] = df['contb_receipt_dt'].map(transformDate) df.head() #查看老兵(捐献者职业)主要支持谁 :查看老兵们捐赠给谁的钱最多 #1.将老兵对应的行数据取出 df['contbr_occupation'] == 'DISABLED VETERAN' old_bing = df.loc[df['contbr_occupation'] == 'DISABLED VETERAN'] #2.根据候选人分组 old_bing.groupby(by='cand_nm')['contb_receipt_amt'].sum() df['contb_receipt_amt'].max() #捐赠金额最大的人的职业以及捐献额 .通过query("查询条件来查找捐献人职业") df.query('contb_receipt_amt == 1944042.43')
matplotlib
一、Matplotlib基础知识
Matplotlib中的基本图表包括的元素
- x轴和y轴 axis
水平和垂直的轴线
- x轴和y轴刻度 tick
刻度标示坐标轴的分隔,包括最小刻度和最大刻度
- x轴和y轴刻度标签 tick label
表示特定坐标轴的值
- 绘图区域(坐标系) axes
实际绘图的区域
- 坐标系标题 title
实际绘图的区域
- 轴标签 xlabel ylabel
实际绘图的区域
import numpy as np import pandas as pd import matplotlib.pyplot as plt from pandas import Series,DataFrame %matplotlib inline # 帮助显示图像
包含单条曲线的图
注意:y,x轴的值必须为数字
x=[1,2,3,4,5] y=[2,4,6,8,10] plt.plot(x,y)
绘制抛物线
x = np.linspace(-np.pi,np.pi,num=10) y = x**2 plt.plot(x,y)
绘制正弦曲线图
x = x y = np.sin(x) plt.plot(x,y)
包含多个曲线的图
1、连续调用多次plot函数
plt.plot(x,y)
plt.plot(x-1,y+2)
2、也可以在一个plot函数中传入多对X,Y值,在一个图中绘制多个曲线
plt.plot(x,y,x+1,y-1)
将多个曲线图绘制在一个table区域中:对象形式创建表图
- a=plt.subplot(row,col,loc) 创建曲线图
- a.plot(x,y) 绘制曲线图
ax1 = plt.subplot(2,2,1) ax1.plot(x,y) ax2 = plt.subplot(222) ax2.plot(x+1,y-2) ax3 = plt.subplot(223) ax3.plot(x+3,y-1) ax4 = plt.subplot(224) ax4.plot(x**2,y-2)
坐标轴界限
axis方法:设置x,y轴刻度值的范围
plt.axis([xmin,xmax,ymin,ymax])
plt.plot(x,y)
plt.axis([-6,6,-2,2])
plt.axis('off')
关闭坐标轴
plt.plot(x,y) plt.axis('off')
设置画布比例:plt.figure(figsize=(a,b)) a:x刻度比例 b:y刻度比例 (2:1)表示x刻度显示为y刻度显示的2倍
plt.figure(figsize=(16,8))
plt.plot(x,y)
坐标轴标签
- s 标签内容
- color 标签颜色
- fontsize 字体大小
- rotation 旋转角度
- plt的xlabel方法和ylabel方法 title方法
plt.plot(x,y) plt.xlabel('haha') plt.ylabel('hehe') plt.title('heihei')
图例
两种传参方法:
- 分别在plot函数中增加label参数,再调用plt.legend()方法显示
- 直接在legend方法中传入字符串列表
plt.plot(x,y,label='temp') plt.plot(x-1,y+3,label='dist') plt.legend()
legend的参数
- loc参数
- loc参数用于设置图例标签的位置,一般在legend函数内
- matplotlib已经预定义好几种数字表示的位置
plt.plot(x,y,label='temp') plt.plot(x-1,y+3,label='dist') plt.legend(loc=3)
ncol控制图例中有几列,在legend中设置ncol
plt.plot(x,y,label='temp') plt.plot(x-1,y+3,label='dist') plt.legend(loc=3,ncol=2)
保存图片
使用figure对象的savefig函数来保存图片
fig = plt.figure()---必须放置在绘图操作之前
figure.savefig的参数选项
- filename
含有文件路径的字符串或Python的文件型对象。图像格式由文件扩展名推断得出,例如,.pdf推断出PDF,.png推断出PNG (“png”、“pdf”、“svg”、“ps”、“eps”……) - dpi
图像分辨率(每英寸点数),默认为100 - facecolor ,打开保存图片查看 图像的背景色,默认为“w”(白色)
fig = plt.figure() plt.plot(x,y,label='temp') plt.plot(x-1,y+3,label='dist') plt.legend(loc=3,ncol=2) fig.savefig('./123.png',dpi=300)
设置plot的风格和样式
plot语句中支持除X,Y以外的参数,以字符串形式存在,来控制颜色、线型、点型等要素,语法形式为:
plt.plot(X, Y, 'format', ...)
参数color或c
plt.plot(x,y,c='red',alpha=0.5,ls='steps',lw=3)
颜色值的方式
- 别名
- color='r'
- 合法的HTML颜色名
- color = 'red'
- HTML十六进制字符串
- color = '#eeefff'
- 归一化到[0, 1]的RGB元组
- color = (0.3, 0.3, 0.4)
透明度
alpha参数
线型
参数linestyle或ls
线宽
linewidth或lw参数
点型
- marker 设置点形
- markersize 设置点形大小
plt.plot(x,y,marker='2')
# 绘制线 plt.plot(x1,y1,x2,y2) # 网格线 plt.grid(True) axes.grid(color,ls,lw,alpha) # 获取坐标系 plt.subplot(n1,n2,n3) # 坐标轴标签 plt.xlabel() plt.ylabel() # 坐标系标题 plt.title() # 图例 plt.legend([names],ncol=2,loc=1) plt.plot(label='name') # 线风格 -- -. : None step # 图片保存 figure.savefig() # 点的设置 marker markersize markerfacecolor markeredgecolor\width # 坐标轴刻度 plt.xticks(刻度列表,刻度标签列表) plt.yticks() # axes.set_xticks(刻度列表) axes.set_xticklabels(刻度标签列表)
三、2D图形
直方图
- 是一个特殊的柱状图,又叫做密度图。
【直方图的参数只有一个x!!!不像条形图需要传入x,y】
plt.hist()的参数
- bins
直方图的柱数,可选项,默认为10 - color
指定直方图的颜色。可以是单一颜色值或颜色的序列。如果指定了多个数据集合,例如DataFrame对象,颜色序列将会设置为相同的顺序。如果未指定,将会使用一个默认的线条颜色 - orientation
通过设置orientation为horizontal创建水平直方图。默认值为vertical
data = [1,2,3,3,4,2,5]
plt.hist(data,bins=10)
返回值 :
1: 直方图向量,是否归一化由参数normed设定
2: 返回各个bin的区间范围
3: 返回每个bin里面包含的数据,是一个list
条形图:plt.bar()
- 参数:第一个参数是索引。第二个参数是数据值。第三个参数是条形的宽度
-【条形图有两个参数x,y】
- width 纵向设置条形宽度
- height 横向设置条形高度
bar()、barh()
x = [1,2,3,4,5] y = [2,4,6,8,10] plt.bar(x,y)
plt.barh(x,y)
饼图
【饼图也只有一个参数x】
pie()
饼图适合展示各部分占总体的比例,条形图适合比较各部分的大小
普通各部分占满饼图
plt.pie([1,3,5])
普通未占满饼图:小数/比例
plt.pie([0.2,0.3,0.4])
饼图阴影、分裂等属性设置 #labels参数设置每一块的标签; #labeldistance参数设置标签距离圆心的距离(比例值) #autopct参数设置比例值小数保留位(%.3f%%); #pctdistance参数设置比例值文字距离圆心的距离 #explode参数设置每一块顶点距圆心的长度(比例值,列表); #colors参数设置每一块的颜色(列表); #shadow参数为布尔值,设置是否绘制阴影 #startangle参数设置饼图起始角度
arr=[11,22,31,15] plt.pie(arr,labels=['a','b','c','d'])
#labeldistance参数设置标签距离圆心的距离(比例值) arr=[11,22,31,15] plt.pie(arr,labels=['a','b','c','d'],labeldistance=0.3)
#explode参数设置每一块顶点距圆心的长度(比例值,列表); arr=[11,22,31,15] plt.pie(arr,labels=['a','b','c','d'],labeldistance=0.3,shadow=True,explode=[0.2,0.3,0.2,0.4])
%m.nf m 占位 n 小数点后保留几位 f 是以float格式输出
散点图:因变量随自变量而变化的大致趋势
【散点图需要两个参数x,y,但此时x不是表示x轴的刻度,而是每个点的横坐标!】
scatter()
plt.scatter(x,y)
plt.scatter(x,y,marker='d',c="rbgy") 设置不同的散点颜色
x = np.random.random(size=(30,)) y = np.random.random(size=(30,)) plt.scatter(x,y)
城市气候与海洋的关系研究
导入包
import numpy as np import pandas as pd from pandas import Series,DataFrame import matplotlib.pyplot as plt %matplotlib inline from pylab import mpl mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体 mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
去除没用的列
# 去除没用的列 faenza.head() city_list = [ferrara,torino,mantova,milano,ravenna,asti,bologna,piacenza,cesena,faenza] # 读取的数据 for city in city_list: city.drop(labels='Unnamed: 0',axis=1,inplace=True) # labels删除
显示最高温度于离海远近的关系(观察多个城市)
max_temp = [] #10个城市的最高温度 cities_dist = [] #10个城市距离海洋的距离 for city in city_list: max_temp.append(city['temp'].max()) cities_dist.append(city['dist'].max()) max_temp cities_dist 在方程式中: x:自变量 y:因变量 y = 5x + 4 自变量的变化会导致因变量的变化 plt.scatter(cities_dist,max_temp,c='rbyg') # c=颜色 plt.xlabel('距离') plt.ylabel('最高温度') plt.title('距离和最高温度之间的关系图')
基于当前的关系模式将某一个未知最高温度的城市的最高温度进行预测
机器学习
- 机器学习(ML)和人工智能之间的关系是什么?
- 机器学习是实现人工智能的一种技术手段
- 什么是算法模型(model或者m)?
- 特殊的对象。特殊之处就在于该对象内部集成了某一种还没有求出解的方程。
- 算法模型的作用?
- 实现预测:预测出一个未知的结果
- 实现分类:将一个未知分类的事务归类到已知的类群中
- 重点:算法模型中的方程的解就是预测或者分类的结果
-
样本数据
- 作用:将样本数据带入到算法模型中让其内部的方程有解。至此算法模型就可以实现分类或者预测的功能。
- 训练模型:将样本数据带入到算法模型中让其内部的方程有解。只有训练好的算法模型才可以实现分类或者预测的功能!
- 组成部分:
- 特征数据:自变量
- 目标数据:因变量
-
sk-learn库:封装了大量的算法模型
- 模型的分类:
- 有监督学习:如果模型需要的样本数据必须包含特征数据和目标数据
- 无监督学习:如果模型需要的样本只需要有特征数据
导入sklearn,建立线性回归算法模型对象
- 该模型内部封装的是一个线性方程:y = wx + b
#0.提取样本数据(特征数据,目标数据) feature = np.array(cities_dist) #特征数据 cities_dist(最远距离,变量) feature = feature.reshape(-1, 1) #二维形式的特征数据 target = np.array(max_temp) #目标数据
训练模型调用的方法是fit(X,y),y任意形式(维度)的目标数据,X表示的必须是二维的特征数据
#1.选择一个模型对象进行实例化 from sklearn.linear_model import LinearRegression linner = LinearRegression() #2.训练模型 linner.fit(feature,target) #X,y #3.使用相关的评价指标来评价模型 linner.score(feature,target) #4.实现预测 linner.predict([[222],[333]]) #调用方程:y = 3x + 6
画出回归曲线
#画出回归曲线 x = np.linspace(0,350,num=100) y = linner.predict(x.reshape(-1,1)) plt.scatter(cities_dist,max_temp,c='rbyg') plt.xlabel('距离') plt.ylabel('最高温度') plt.title('距离和最高温度之间的关系图') plt.scatter(x,y)
K-近邻算法(KNN)
如何进行电影分类
众所周知,电影可以按照题材分类,然而题材本身是如何定义的?由谁来判定某部电影属于哪 个题材?也就是说同一题材的电影具有哪些公共特征?这些都是在进行电影分类时必须要考虑的问 题。没有哪个电影人会说自己制作的电影和以前的某部电影类似,但我们确实知道每部电影在风格 上的确有可能会和同题材的电影相近。那么动作片具有哪些共有特征,使得动作片之间非常类似, 而与爱情片存在着明显的差别呢?动作片中也会存在接吻镜头,爱情片中也会存在打斗场景,我们 不能单纯依靠是否存在打斗或者亲吻来判断影片的类型。但是爱情片中的亲吻镜头更多,动作片中 的打斗场景也更频繁,基于此类场景在某部电影中出现的次数可以用来进行电影分类。
1、k-近邻算法原理
简单地说,K-近邻算法采用测量不同特征值之间的距离方法进行分类。
- 优点:精度高(计算距离)、对异常值不敏感(单纯根据距离进行分类,会忽略特殊情况)、无数据输入假定(不会对数据预先进行判定)。
- 缺点:时间复杂度高、空间复杂度高。
- 适用数据范围:数值型和标称型。
工作原理
存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据 与所属分类的对应关系。输人没有标签的新数据后,将新数据的每个特征与样本集中数据对应的 特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们 只选择样本数据集中前K个最相似的数据,这就是K-近邻算法中K的出处,通常K是不大于20的整数。 最后 ,选择K个最相似数据中出现次数最多的分类,作为新数据的分类。
2、在scikit-learn库中使用k-近邻算法
分类问题:from sklearn.neighbors import KNeighborsClassifier
1)用于分类
导包,机器学习的算法KNN、数据蓝蝴蝶
示例:
读取adult.txt文件,最后一列是年收入,并使用KNN算法训练模型,然后使用模型预测一个人的年收入是否大于50
data = pd.read_csv('../data/adults.txt') data.head()
获取年龄、教育程度、职位、每周工作时间作为机器学习数据
获取薪水作为对应结果
feature = data[['age','education_num','occupation','hours_per_week']] target = data['salary']
knn中特征数据是需要参与运算的,所以要保证特征数据必须为数值型的数据
feature.head(2)
数据转换,将String类型数据转换为int
【知识点】map方法,进行数据转换
dic = {} occ_arr = feature['occupation'].unique() for i in range(occ_arr.size): dic[occ_arr[i]] = i dic feature['occupation'] = feature['occupation'].map(dic) 切片:训练数据和预测数据 feature.shape
训练数据 测试数据
#训练数据 x_train = feature[:32500] y_train = target[:32500] #测试数据 x_test = feature[32500:] y_test = target[32500:]
生成算法
from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier(n_neighbors=10) knn.fit(x_train,y_train) knn.score(x_test,y_test)
第二步:预测数据
print('真实的分类结果:',np.array(y_test)) print('模型的分类结果:',knn.predict(x_test))
2、小麦种类预测
读取seeds.tsv文件,最后一列是小麦品种,其他列是小麦特征
3、改进约会网站的匹配效果
读取datingTestSet.txt文件,最后一列是喜欢程度。模型:根据前几列的信息,预测喜欢程度
KNN手写数字识别
import numpy as np import matplotlib .pyplot as plt import pandas as pd from sklearn.neighbors import KNeighborsClassifier
加载数据
#加载数据 img_arr = plt.imread('./data/6/6_66.bmp') plt.imshow(img_arr)
提取数据
img_arr.shape #图片的像素为28*28,对应的numpy数组是二维 #./data/6/6_66.bmp feature = [] target = [] for i in range(10): #i表示的文件夹的名称 for j in range(1,501): img_path = './data/'+str(i)+'/'+str(i)+'_'+str(j)+'.bmp' img_arr = plt.imread(img_path) feature.append(img_arr) target.append(i) #提取样本数据 feature = np.array(feature) #必须保证是二维 target = np.array(target) feature.shape #目前的特征是3维 #特征处理:将三维的特征变形成二维 feature = feature.reshape((5000,-1)) feature.shape
总结:feature特征数据中存放是5000个一维的图片数据
对样本进行拆分
对样本数据进行拆分 #对样本数据进行打乱 np.random.seed(10) np.random.shuffle(feature) np.random.seed(10) np.random.shuffle(target) #拆分 x_train = feature[:4950] y_train = target[:4950] x_test = feature[4950:] y_test = target[4950:]
实例化模型对象,然后对其进行训练
knn = KNeighborsClassifier(n_neighbors=5) knn.fit(x_train,y_train) knn.score(x_test,y_test) print('真实的分类结果:',y_test) print('模型的分类结果:',knn.predict(x_test))
保存模型
from sklearn.externals import joblib joblib.dump(knn,'./knn.m') knn = joblib.load('./knn.m') knn
使用模型识别外部的数字图片
img_arr = plt.imread('./数字.jpg') plt.imshow(img_arr) img_arr.shape eight_img = img_arr[180:235,90:130,:] plt.imshow(eight_img) feature[0].shape
模型可以识别的图片的维度是取决于样本数据的
- 可以识别的图片是28*28像素
- 图片是没有颜色这个维度
eight_img.shape eight_img = eight_img.mean(axis=2) eight_img.shape
对降维之后的图片的像素进行等比例压缩
import scipy.ndimage as ndimage eight_img = ndimage.zoom(eight_img,zoom=(28/55,28/40)) eight_img.shape eight_img = eight_img.reshape(1,-1) eight_img.shape knn.predict(eight_img)