数据分析三剑客

数据分析三剑客:

  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
View Code

输出该股票所有开盘比前日收盘跌幅超过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
View Code

假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?

df_2010 = df['2010':'2019']
df_2010
View Code

买入股票花费的钱数

df_monthly = df_2010.resample('M').first()
df_monthly
View Code

昨天的收盘价

last_price = df_2010['close'][-1] 
recv_monry = df_yearly['open'].sum()*1200 + last_price*1000
recv_monry - cost_money
View Code

 

处理丢失数据

有两种丢失数据:

  • 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) # 合并
View Code

 

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)  # 合并
View Code

 

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表示连接方式
View Code

 

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')  # 
View Code

 

当两张表没有可进行连接的列时,可使用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是表示连接方式
View Code

 

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']})
View Code

 

人口分析

需求:

  • 导入文件,查看原始数据
  • 将人口数据和各州简称数据进行合并
  • 将合并的数据中重复的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)
View Code

将人口数据和各州简称数据进行合并

#将人口数据和各州简称数据进行合并
abb_pop = pd.merge(abb,pop,left_on='abbreviation',right_on='state/region',how='outer')
abb_pop.head(2)
View Code

将合并的数据中重复的abbreviation列进行删除

#将合并的数据中重复的abbreviation列进行删除
abb_pop.drop(labels='abbreviation',axis=1,inplace=True)
abb_pop.head(2)
View Code

查看存在缺失数据的列

#查看存在缺失数据的列
abb_pop.isnull().any(axis=0)
View Code

找到有哪些state/region使得state的值为NaN,进行去重操作

#找到有哪些state/region使得state的值为NaN,进行去重操作
#1.state列中哪些值为空
abb_pop['state'].isnull()
View Code

为找到的这些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'
View Code

合并各州面积数据areas

#合并各州面积数据areas
abb_pop_area = pd.merge(abb_pop,area,how='outer')
abb_pop_area.head(3)
View Code

我们会发现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
View Code

去除含有缺失数据的行

#去除含有缺失数据的行
abb_pop_area.drop(labels=indexs,axis=0,inplace=True)
View Code

找出2010年的全民人口数据

#找出2010年的全民人口数据
abb_pop_area.query('year == 2010 & ages == "total"')
View Code

计算各州的人口密度

#计算各州的人口密度
abb_pop_area['midu'] = abb_pop_area['population'] / abb_pop_area['area (sq. mi)']
abb_pop_area.head(2)
View Code

排序,并找出人口密度最高的五个州 df.sort_values()

abb_pop_area.sort_values(by='midu',axis=0,ascending=False).head(5)
View Code

 

数据竞赛平台

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]
View Code

使用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
View Code

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
View Code

使用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)]
View Code

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]
View Code

随机抽样

当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())
View Code

 

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'           
 }
View Code
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')
View Code

 

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')

图例

legend方法

两种传参方法:

  • 分别在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删除 
View Code

显示最高温度于离海远近的关系(观察多个城市)

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('距离和最高温度之间的关系图')
View Code

基于当前的关系模式将某一个未知最高温度的城市的最高温度进行预测

机器学习

  • 机器学习(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)     #目标数据
View Code

   训练模型调用的方法是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
View Code

  画出回归曲线

#画出回归曲线
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)
View Code

 

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']
View Code

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
View Code

训练数据 测试数据

#训练数据 
x_train = feature[:32500]
y_train = target[:32500]
#测试数据
x_test = feature[32500:]
y_test = target[32500:]
View Code

生成算法

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=10)
knn.fit(x_train,y_train)
knn.score(x_test,y_test)
View Code

第二步:预测数据

print('真实的分类结果:',np.array(y_test))
print('模型的分类结果:',knn.predict(x_test))
View Code
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)
View Code

提取数据

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
View Code

总结: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:]
View Code

实例化模型对象,然后对其进行训练

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))
View Code

保存模型

from sklearn.externals import joblib
joblib.dump(knn,'./knn.m')

knn = joblib.load('./knn.m')
knn
View Code

使用模型识别外部的数字图片

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
View Code

模型可以识别的图片的维度是取决于样本数据的

  • 可以识别的图片是28*28像素
  • 图片是没有颜色这个维度
eight_img.shape
eight_img = eight_img.mean(axis=2)
eight_img.shape
View Code

对降维之后的图片的像素进行等比例压缩

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)
View Code

 

posted @ 2019-10-16 16:37  驰念  阅读(1127)  评论(0编辑  收藏  举报