python数据分析与算法 之 六 数据分析

  • 数据分析:是把隐藏在一些看似杂乱无章的数据背后的信息提炼出来,总结出所研究对象的内在规律

  • 数据分析三剑客:Numpy,Pandas,Matplotlib

6.1Numpy

  • NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。

6.1.1创建ndarray

使用np.array()创建

  • 一维数据创建

    import numpy as np
    np.array([1,2,3])
    

  • 二维数据创建

    import numpy as np
    np.array([[4,5,6],[7,8,9]])
    

    import numpy as np
    np.array([[1,'two',3],[4,5,6]])
    

    注意:

    • numpy默认ndarray的所有元素的类型是相同的

    • 如果传进来的列表中包含不同的类型,则统一为同一类型,优先级:str>float>int

  • 使用matplotlib获取一个数组

    • 使用matplotlib.pyplot获取一个numpy数组,数据来源于一张图片

      import matplotlib.pylab as plt
      img_arr = plt.imread('./cat.jpg')
      plt.imshow(img_arr)
      

    #操作该numpy数据,该操作会同步到图片中
    plt.imshow(img_arr-100)
    

使用np的routines函数创建

  • np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) 等差数列

    np.linspace(0,100,num=20)
    

  • np.arange([start, ]stop, [step, ]dtype=None)

    np.arange(0,100,2)
    

  • np.random.randint(low, high=None, size=None, dtype='l').

    np.random.randint(0,100,size=[4,5])
    

    np.random.randint(0,100,size=[2,5])
    

    固定随机性

    #固定随机性
        #随机因子:系统的时间
    np.random.seed(100)
    arr = np.random.randint(0,100,size=(4,5))
    

  • np.random.random(size=None)

    np.random.random(size=(4,5))
    

  • np.random.randn(d0,d1,...dn) 标准正态分布

6.1.2 ndarray的属性

  • 4个必记参数:

    • ndim:维度

    • shape:形状(各维度的长度)

    • size:总长度

    • dtype:元素类型

6.1.3ndarray的基本操作

1.索引

  • 一维与列表完全一致 多维时同理

    import numpy as np
    arr = np.random.randint(0,100,size=[4,5])
    arr
    # array([[60, 49, 97, 33, 14],
    #       [94, 21, 59, 48,  5],
    #       [33, 64, 85, 81, 17],
    #       [16, 38, 30, 32, 56]])
    
    arr[1]
    # array([94, 21, 59, 48,  5])
    
    arr[1][2]
    # 59
    

2.切片

  • 一维与列表完全一致 多维时同理

    import numpy as np
    arr = np.random.randint(0,100,size=[4,5])
    
    • 原始数组 : arr

    • 获取二维数组的前两行: arr[0:2]

    • 获取二维数组的前两列: arr[:,0:2]

    • 获取二维数组的前两行的前两列: arr[0:2,0:2]

    • 行倒序: arr[::-1]

    • 列倒序 : arr[:,::-1]

    • 全部倒序 : arr[::-1,::-1]

3.变形

  • 使用arr.reshape()函数,注意参数是一个tuple!

    import numpy as np
    arr = np.random.randint(0,100,size=[4,5])
    arr
    

  • 基本使用

    • 将一维数组变形成多维数组

      arr_1.reshape((1,20))  #二维数组
      

      arr_1.reshape((4,5))
      

      arr_1.reshape((-1,4))    # -1表示自动计算行数
      

    • 将多维数组变形成一维数组

      arr_1 = arr.reshape((20,))
      arr_1      # 一维数组
      

4.对图片的操作

import matplotlib.pylab as plt
img_arr = plt.imread('./cat.jpg')
  • plt.imshow(img_arr)

  • 图片形状 img_arr.shape

  • 图片的左右倒置 : plt.imshow(img_arr[:,::-1,:])

    • 图片的上下倒置 :plt.imshow(img_arr[::-1,:,:])

    • 图片的全倒置 plt.imshow(img_arr[::-1,::-1,:])

    • 裁剪操作 plt.imshow(img_arr[100:350,150:550,:])

5.级联

  • np.concatenate()

  • 注意事项:

    • 级联的参数是列表:一定要加中括号或小括号

    • 维度必须相同

    • 形状相符:在维度保持一致的前提下,如果进行横向(axis=1)级联,必须保证进行级联的数组行数保持一致。如果进行纵向(axis=0)级联,必须保证进行级联的数组列数保持一致。

    • 可通过axis参数改变级联的方向

    示例:

    import numpy as np
    arr = np.random.randint(0,100,size=[4,5])
    arr
    

    np.concatenate((arr,arr),axis=0)   # 0表示纵向拼接
    

    np.concatenate((arr,arr),axis=1)    #1表示横向拼接
    

    import matplotlib.pylab as plt
    img_arr = plt.imread('./cat.jpg')
    plt.imshow(img_arr)
    

  • 合并两张照片

    img_3 = np.concatenate((img_arr,img_arr,img_arr),axis=1)    #1表示横向拼接
    plt.imshow(img_3)
    

    img_9 = np.concatenate((img_3,img_3,img_3),axis=0)
    plt.imshow(img_9)
    

6.1.4ndarray的聚合操作

import numpy as np
arr = np.random.randint(0,100,size=[4,5])
arr

1.求和

  • np.sum

2.最大最小值

  • np.max/ np.min

3.平均值

  • np.mean()

4.其他聚合操作

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              幂运算

6.1.5 ndarray的排序

快速排序

  • np.sort()与ndarray.sort()都可以,但有区别:

    • np.sort() 不改变输入

    • ndarray.sort()本地处理,不占用空间,但改变输入

6.2 Pandas

  • pandas的导入

    import pandas as pd
    from pandas import Series,DataFrame
    import numpy as np
    

6.2.1 Series

  • Series是一种类似与一维数组的对象,由下面两个部分组成:

    • values:一组数据(ndarray类型)

    • index:相关的数据索引标签

1.Series的创建

由列表创建

默认索引为0到N-1的整数型索引

  • "显示索引"可增加Series数据的可读性

Series(data=[1,2,3])   #默认的0,1,2是隐式索引

Series(data=[1,2,3],index=['a','b','c'])   # a,b,c是显示索引

由numpy数组创建
s = Series(data=np.random.randint(0,100,size=(4,)))     
s          #注意 Series是一个一维数组

  • 练习

    #练习1:使用多种方法创建以下Series,命名为s1:
    语文 150
    数学 150
    英语 150
    理综 300
    
    s1 = Series(data=[150,150,150,300],index=['语文','数学','英语','理综'])
    s1
    

2.Series的索引

  • 可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里一个列表取多个索引(此时返回的是一个Series类型)。

显式索引
  • 使用index中的元素作为索引值

  • 使用s.loc[](推荐):注意,loc中括号中放置的一定是显示索引

    s = Series(data=np.random.randint(0,100,size=(4,)),index=['a','b','c','d'])
    s
    

    s[0]
    s['a']
    

隐式索引
  • 使用整数作为索引值

  • 使用.iloc[](推荐):iloc中的中括号中必须放置隐式索引

3.Series的切片

显示索引切片
  • index和loc

    s[0:3]
    

4.Series的基本操作

  • 可以通过shape,size,index,values等得到series的属性

  • 可以使用s.head(),tail()分别查看前n个和后n个值

  • 对Series元素进行去重 s.unique()

    s2 = Series(data=[11,11,22,33,22,44,44,33,55,66,66,66])
    s2.unique()
    

  • 当索引没有对应的值时,可能出现缺失数据显示NaN(not a number)的情况

    • 使得两个Series进行相加

      s1 = Series(data=[1,2,3],index=['a','b','c'])
      s2 = Series(data=[1,2,3],index=['a','b','d'])
      s = s1 + s2
      

    • 可以使用pd.isnull(),pd.notnull(),或s.isnull(),notnull()函数检测缺失数据

    • s[[True,False,False,True]]

    • s[s.notnull()]

    • s[s.isnull()]

     

5.Series的运算

  • / * + -

  • add() sub() mul() div() : s1.add(s2,fill_value=0)

  • Series之间的运算

    • 在运算中自动对齐不同索引的数据

    • 如果索引不对应,则补NaN

  • 练习

    想一想Series运算和ndarray运算的规则有什么不同?
    
    新建另一个索引包含“文综”的Series s2,并与s2进行多种算术操作。
    

4.2.2 DataFrame

  • DataFrame是一个【表格型】的数据结构。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。

    • 行索引:index

    • 列索引:columns

    • 值:values

1.DataFrame的创建

  • 最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。此外,DataFrame会自动加上每一行的索引。使用字典创建的DataFrame后,则columns参数将不可被使用。同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。

使用ndarray创建
arr = np.array([1,2,3])
type(arr)

  • DataFrame属性:values、columns、index、shape

    data = data=np.random.randint(0,100,size=(3,4))
    DataFrame(data=data)
    

    DataFrame(data=np.random.randint(0,100,size=(3,4)),index=['a','b','c'],columns=['A','B','C','D'])
    

使用字典创建
  • 创建一个表格用于展示张三,李四,王五的java,python的成绩

    dic = {
        '张三':[11,22,33,44],
        '李四':[55,66,77,88]
    }
    df_score = DataFrame(data=dic)
    df_score
    

    dic = {
        '张三':[11,22,33,44],
        '李四':[55,66,77,88]
    }
    df_score = DataFrame(data=dic,index=['语文','数学','英语','理综'])
    df_score
    

2.DataFrame的索引

对列进行索引
  • 通过类似字典的方式 df['q']

  • 通过属性的方式 df.q

  • 可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。

    df=DataFrame(data=np.random.randint(0,100,size=(3,4)),index=['a','b','c'],columns=['A','B','C','D'])
    df
    

    • 获取第一列

      df['A']        #注意 DataFrame 有了显示索引就不能使用隐式索引,否则会报错
      

    • 获取前两列

      df[['A','B']]
      

对行进行索引
  • 使用.loc[]加index来进行行索引

    df.loc[['a','b']]    # loc + 显示索引
    

  • 使用.iloc[]加整数来进行行索引

    df.iloc[[0,1]]   # iloc + 隐式索引
    

  • 同样返回一个Series,index为原来的columns。

3.对元素索引

  • 使用列索引

  • 使用行索引(iloc[3,1] or loc['C','q']) 行索引在前,列索引在后

    df.loc['a','B']
    

    df.loc[['a','b'],'B']
    

4.切片

  • 注意 直接用中括号时:

    • 索引表示的是列索引

    • 切片表示的是行切片

  • 切出前两行

    #切出前两行
    df['a':'b']
    df[0:2]
    

  • 切出前两列

    df.loc[:,'A':'B']
    

5.DataFrame的运算

  • 同Series一样:

    • 在运算中自动对齐不同索引的数据

    • 如果索引不对应,则补NaN

  • 练习

    dic = {
        '张三':[11,22,33,44],
        '李四':[55,66,77,88]
    }
    df_score = DataFrame(data=dic,index=['语文','数学','英语','理综'])
    
    qizhong = df_score
    qimo = df_score
    
    #1.假设ddd是期中考试成绩,ddd2是期末考试成绩,请自由创建ddd2,并将其与ddd相加,求期中期末平均值。
    (qizhong + qimo)/2
    

    #2.假设张三期中考试数学被发现作弊,要记为0分,如何实现?
    qizhong.loc['数学','张三'] = 0
    qizhong
    

    #3.李四因为举报张三作弊立功,期中考试所有科目加100分,如何实现?
    qizhong['李四'] += 100
    qizhong
    

    #4.后来老师发现有一道题出错了,为了安抚学生情绪,给每位学生每个科目都加10分,如何实现?
    qizhong += 10
    qizhong
    

6.处理丢失数据

  • 有两种丢失数据:

    • None

    • np.nan(NaN)

None
  • None是Python自带的,其类型为python object。因此,None不能参与到任何计算中。

np.nan(NaN)
  • np.nan是浮点类型,能参与到计算中。但计算的结果总是NaN。

pandas中None与np.nan
  • pandas中None与np.nan都视作np.nan

    import numpy as np
    import pandas as pd
    from pandas import Series,DataFrame
    
    df = DataFrame(data=np.random.randint(0,100,size=(8,6)))
    df
    

    df.iloc[2,4] = None
    df.iloc[3,3] = np.nan
    df.iloc[5,2] = None
    df.iloc[2,1] = None
    df
    

pandas处理空值操作
  • 判断函数

    结论:将df.notnull().all(axis=1)作为源数据的行索引,就可以将空对应的行删除

    • isnull()

      #固定搭配
      df.isnull().any(axis=1)
      

    • notnull()

      #固定搭配
      df.notnull().all(axis=1)
      

      df.loc[df.notnull().all(axis=1)]
      

  • dropna(): 过滤丢失数据

    • 可以选择过滤的是行还是列(默认为行):axis中0表示行,1表示的列

    df.dropna(axis=0)   #删除有空值的行
    

     

  • 填充函数 Series/DataFrame

    • fillna(): 填充丢失数据, 一般使用value和method参数

    df.fillna(method='ffill',axis=0)   #用前一个数覆盖
    

    df.fillna(method='bfill',axis=0)  #用后一个数覆盖
    

    df.fillna(value=666)    #一般不用
    

     

  • 练习

    1.简述None与NaN的区别
    2.假设张三李四参加模拟考试,但张三因为突然想明白人生放弃了英语考试,因此记为None,请据此创建一个DataFrame,命名为ddd3
    3.老师决定根据用数学的分数填充张三的英语成绩,如何实现? 用李四的英语成绩填充张三的英语成绩?
    
  • 练习

    #数据说明: 
        数据是1个冷库的温度数据,1-7对应7个温度采集设备,1分钟采集一次。
        
    #数据处理目标:
    	用1-4对应的4个必须设备,通过建立冷库的温度场关系模型,预估出5-7对应的数据。最后每个冷库中仅需放置4个设备,取代放置7个设备。f(1-4) --> y(5-7)
    
    #数据处理过程:
    	1、原始数据中有丢帧现象,需要做预处理;
        2、matplotlib 绘图;
        3、建立逻辑回归模型。
    
    #无标准答案,按个人理解操作即可,请把自己的操作过程以文字形式简单描述一下,谢谢配合。
    

    原样本部分 : E:\飞秋\数据结构+算法\day03\面试题\测试数据.xlsx

    • 1.数据的读取

      import numpy as np
      import pandas as pd
      from pandas import Series,DataFrame
      df = pd.read_excel('./测试数据.xlsx')
      df.head(5)    #取前五行数据
      

    • 2.删除无用的两列

      df.drop(labels=['none','none1'],axis=1,inplace=True)   #1为列,inplace=True表示作用于原数据
      df.head(5)
      

    • 3.空数据的处理

      • 处理方法一:

        df.loc[df.notnull().all(axis=1)]    #删除空对应的行
        

      • 处理方法二:

        df.fillna(method='ffill',axis=0)
        

        df.fillna(method='ffill',axis=0).fillna(method='bfill',axis=0)
        

    • 4.检测df的列中是否存在空值

      • 方式一:

        df.isnull().any(axis=0)
        

      • 方式二:

        df.notnull().all(axis=0)
        

         

7.使用pd.concat()级联

  • pandas使用pd.concat函数,与np.concatenate函数类似,只是多了一些参数:

    • objs

    • axis=0

    • keys

    • join='outer' / 'inner':表示的是级联的方式,outer会将所有的项进行级联(忽略匹配和不匹配),而inner只会将匹配的项级联到一起,不匹配的不级联

    • ignore_index=False

匹配级联
import numpy as np
import pandas as pd
from pandas import Series,DataFrame

df1 = DataFrame(data=np.random.randint(0,100,size=(3,3)),index=['A','B','C'],columns=['a','b','c'])
df2 = DataFrame(data=np.random.randint(0,100,size=(3,3)),index=['A','B','D'],columns=['a','b','d'])
df1

df2

pd.concat((df1,df1),axis=0)   # 0表示列

不匹配级联
  • 不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致

  • 有2种连接方式:

    • 外连接:补NaN(默认模式)

      pd.concat((df1,df2),axis=0)   # 0表示列
      

    • 内连接:只连接匹配的项

      pd.concat((df1,df2),axis=0,join='inner')   # 0表示列
      

8.使用pd.merge()合并

  • merge与concat的区别在于,merge需要依据某一共同的列来进行合并

  • 使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。

  • 注意每一列元素的顺序不要求一致

  • 参数:

    • how:out取并集 inner取交集

    • on:当有多列相同的时候,可以使用on来指定使用那一列进行合并,on的值为一个列表

一对一合并
import numpy as np
import pandas as pd
from pandas import Series,DataFrame

df1 = DataFrame({'employee':['Bob','Jake','Lisa'],
                'group':['Accounting','Engineering','Engineering'],
                })
df1

df2 = DataFrame({'employee':['Lisa','Bob','Jake'],
                'hire_date':[2004,2008,2012],
                })
df2

pd.merge(df1,df2,how='inner')

多对一合并
df3 = DataFrame({
    'employee':['Lisa','Jake'],
    'group':['Accounting','Engineering'],
    'hire_date':[2004,2016]})
df3

df4 = DataFrame({'group':['Accounting','Engineering','Engineering'],
                       'supervisor':['Carly','Guido','Steve']
                })
df4

pd.merge(df3,df4)

多对多合并
  • 内合并与外合并:out取并集 inner取交集

    • 内合并:只保留两者都有的key(默认模式)

    • 外合并 how='outer':补NaN

df5 = DataFrame({'group':['Engineering','Engineering','HR'],
                'supervisor':['Carly','Guido','Steve']
                })
df5

  • 外连接 outer 能连接就连接,不能连就补空

    pd.merge(df1,df5,how='outer',on='group')   # outer 能连接就连接,不能连就补空
    

  • 内连接inner 能连接就连接,不能连就删除

    pd.merge(df1,df5,how='inner',on='group')   # inner 能连接就连接,不能连就删除
    

  • 左连接 left

    pd.merge(df1,df5,how='left',on='group')   
    

  • 右连接

    pd.merge(df1,df5,how='right',on='group')   
    

key的规范化
  • 当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名

    df1 = DataFrame({'employee':['Jack',"Summer","Steve"],
                     'group':['Accounting','Finance','Marketing']})
    df1
    

    df2 = DataFrame({'employee':['Jack','Bob',"Jake"],
                     'hire_date':[2003,2009,2012],
                    'group':['Accounting','sell','ceo']})
    df2
    

    pd.merge(df1,df2)
    

  • 当两张表没有可进行连接的列时,可使用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')
    

6.2.3 Pandas高级操作

1.删除重复元素

  • 使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True

  • keep参数:指定保留哪一重复的行数据

    #创建一个df
    import numpy as np
    import pandas as pd
    from pandas import Series,DataFrame
    
    df = DataFrame(data=np.random.randint(0,100,size=(8,6)))
    df
    

    • 1.手动将df的某几行设置成相同的内容

      df.iloc[1] = [6,6,6,6,6,6,]
      df.iloc[3] = [6,6,6,6,6,6,]
      df.iloc[7] = [6,6,6,6,6,6,]
      df
      

    • 使用drop_duplicates()函数删除重复的行

      • drop_duplicates(keep='first/last'/False)

      df.drop_duplicates(keep='first')    #保留第一个重复的行
      df.drop_duplicates(keep='last')     #保留第一个重复的行
      df.drop_duplicates(keep=False)      #删除所有重复的行
      

2.映射

替换
  • replace()函数:替换元素

    • 使用replace()函数,对values进行映射操作

  • 单值替换

    • 普通替换: 替换所有符合要求的元素:to_replace=15,value='e'

    • 按列指定单值替换: to_replace={列标签:替换值} value='value'

      df.replace(to_replace=2,value='seven')
      

      df.replace(to_replace={88:"7777777"})
      

      df.replace(to_replace={3:6},value='first')    # 3是列索引,6 是将什么值替换,value表示替换成什么值
      

  • 多值替换

    • 列表替换: to_replace=[] value=[]

    • 字典替换(推荐) to_replace={to_replace:value,to_replace:value}

  • 注意:DataFrame中,无法使用method和limit参数

映射
  • map()函数:新建一列 , map函数并不是df的方法,而是series的方法

    • map()可以映射新一列数据

    • map()中可以使用lambd表达式

    • map()中可以使用方法,可以是自定义的方法 eg:map({to_replace:value})

    • 注意 map()中不能使用sum之类的函数,for循环

  • 需求一 :新增一列:给df中,添加一列,该列的值为中文名对应的英文名

    dic = {
        'name':['周杰伦','张三','周杰伦'],
        'salary':[15000,20000,15000]
    }
    df = DataFrame(data=dic)
    df
    

    #映射关系表
    dic1 = {
        '周杰伦':'Jay',
        '张三':'Tom'
    }
    df['E-name'] = df['name'].map(dic1)
    df
    

  • map当做一种运算工具,至于执行何种运算,是由map函数的参数决定的(参数:lambda,函数)

    • 注意:并不是任何形式的函数都可以作为map的参数。只有当一个函数具有一个参数且有返回值,那么该函数才可以作为map的参数。

    • 使用自定义函数

      def after_salary(s):
          return (s-3000)*0.5
      
      #超过3000部分的钱缴纳50%的税
      df['after_salary'] = df['salary'].map(after_salary)
      df
      

3. 使用聚合操作对数据异常值检测和过滤

  • 使用df.std()函数可以求得DataFrame对象每一列的标准差

  • 示例:

    • 创建一个1000行3列的df 范围(0-1),求其每一列的标准差

      df = DataFrame(data=np.random.random(size=(1000,3)),columns=['A','B','C'])
      df
      

      • 对df应用筛选条件,去除标准差太大的数据:假设过滤条件为 C列数据大于两倍的C列标准差

        twice_std = df['C'].std()*2     # std 是求标准差
        twice_std
        

      • 对异常值进行清洗和过滤

        df['C'] > twice_std
        df.loc[df['C'] > twice_std]
        drop_indexs = df.loc[df['C'] > twice_std].index
        df.drop(labels=drop_indexs,axis=0)
        

4.排序

  • 使用.take()函数排序

  • take()函数接受一个索引列表,用数字表示,使得df根据列表中索引的顺序进行排序 eg:df.take([1,3,4,2,5])

  • 示例:

    • 可以借助np.random.permutation()函数随机排序

      df.take(indices=[1,2,0],axis=1).take(indices=np.random.permutation(1000),axis=0)[0:10]   # axis中0表示行,1表示列 ,indices只能用隐式索引
      

    • np.random.permutation(x)可以生成x个从0-(x-1)的随机数列

随机抽样
  • 当DataFrame规模足够大时,直接使用np.random.permutation(x)函数,就配合take()函数实现随机抽样

5. 数据分类处理【重点】

  • 数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。

    数据分类处理:

    • 分组:先把数据分为几组

    • 用函数处理:为不同组的数据应用不同的函数以转换数据

    • 合并:把不同组得到的结果合并起来

    数据分类处理的核心:

    • groupby()函数

    • groups属性查看分组情况

    • eg: df.groupby(by='item').groups

分组
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]})
df

  • 使用groupby实现分组

    • 该函数可以进行数据的分组,但是不显示分组情况

    df.groupby(by='item',axis=0)   # 0表示列
    

  • 使用groups查看分组情况

    df.groupby(by='item',axis=0).groups
    

  • 分组后的聚合操作:分组后的成员中可以被进行运算的值会进行运算,不能被运算的值不进行运算

    #给df创建一个新列,内容为各个水果的平均价格
    df.groupby(by='item',axis=0).mean()   #mean 求均值
    

    mean_price_s = df.groupby(by='item',axis=0)['price'].mean()
    mean_price_s
    

    #创建映射关系表
    dic = mean_price_s.to_dict()
    
    df['item'].map(dic)
    df['mean_price'] = df['item'].map(dic)
    df
    

6. 高级数据聚合

  • 使用groupby分组后,也可以使用transform和apply提供自定义函数实现更多的运算

    • df.groupby('item')['price'].sum() <==> df.groupby('item')['price'].apply(sum)

    • transform和apply都会进行运算,在transform或者apply中传入函数即可

    • transform和apply也可以传入一个lambda表达式

    #apply :未经过映射的结果返回
    def my_mean(p):
        sum = 0
        for i in p:
            sum += i
        return sum/len(p)
    
    df.groupby(by='item')['price'].apply(my_mean)
    

    #transform :经过映射的结果返回
    def my_mean(p):
        sum = 0
        for i in p:
            sum += i
        return sum/len(p)
    
    df.groupby(by='item')['price'].transform(my_mean)
    

6.3Matplotlib

  • 存在于上述Series中

6.4使用tushare包获取某股票的历史行情数据

链接地址 : http://tushare.org/trading.html#id2

import pandas as pd
from pandas import Series,DataFrame
import numpy as np

import tushare as ts

df = ts.get_k_data(code='600519',start='2000-01-01') #
df.to_csv('./maotai.csv')
df = pd.read_csv('./maotai.csv')
df

  • 删除df中的某一列

    df.drop(labels='Unnamed: 0',axis=1,inplace=True)  
    #1表示列,0表示行,inplace=True 将删除后的数据同步映射回原数据
    df
    

  • 将df中的date列作为原数据的行索引

    #将df总的date这一列作为源数据的行索引,将字符串i形式的时间数据转换成时间类型
    df = pd.read_csv('./maotai.csv',index_col='date',parse_dates=['date'])  # index_col将一列转换成一行   parse_dates=['date'] 将某一行当做索引
    #删除df中的某一列               
    df.drop(labels='Unnamed: 0',axis=1,inplace=True)
    df.head(5)
    

    • 验证行索引的数据类型

     

  • 需求一 :输出该股票所有收盘比开盘上涨3%以上的日期

    # 1. (收盘-开盘)/开盘 > 0.03
    ((df['close'] - df['open'])/df['open'] > 0.03)
    

    #2.一旦遇到了一组布尔值,直接将布尔值作为源数据的行索引
    df.loc[((df['close'] - df['open'])/df['open'] > 0.03)]
    

    # 3. 将行索引取出
    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手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?

    # 2010 - 2019
    new_df = df['2010-01-01':'2019-09-04']
    new_df
    

    # 将买票对应的行数据找出
        #在new_df中将每个月的第一个交易日的行数据取出
        #将每一行的open值取出
    new_df.resample('M')      #resample :数据的重新取样, 'A':年,'M';月,'D':天
    

    df_month = new_df.resample('M').first()     #方法自身问题
    

    df_year = new_df.resample('A').last()
    

    # 19年只能买不能卖
    df_year = new_df.resample('A').last()[:-1]
    

    #计算买入股票一共花了多少钱
    cost_monty = df_month['open'].sum()*100
    cost_monty
    

    #计算买入股票一共收入多少钱
    recv_money = df_year['open'].sum()*1200
    recv_money
    

    #将19年手中剩余的股票进行估价,将估价的值也计算到收益中
    recv_monry = 900 * new_df[-1:]['open'] + recv_monry
    recv_monry
    

    #计算收入
    recv_monry - cost_monty
    

6.5级联与合并的应用

案例分析:美国各州人口数据分析

  • 需求:

    • 导入文件,查看原始数据

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

    • 将合并的数据中重复的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
    
    • 1.导入文件,查看原始数据

      abb = pd.read_csv('./data/state-abbrevs.csv')
      pop = pd.read_csv('./data/state-population.csv')
      area = pd.read_csv('./data/state-areas.csv')
      

       

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

      abb_pop = pd.merge(abb,pop,left_on='abbreviation',right_on='state/region',how='outer') #how='outer'保证数据的完整性
      abb_pop.head(5)
      

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

      abb_pop.drop(labels='abbreviation',axis=1,inplace=True)   ##drop函数 1 为列
      abb_pop.head()    
      

    • 4.查看存在缺失数据的列

      abb_pop.isnull().any(axis=0)    # 0 表示列
      

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

      • a.找出 state列的空值

        abb_pop['state'].isnull()
        abb_pop.loc[abb_pop['state'].isnull()]    #就得到了state列中空值对应的行数据
        

      • b.找出空值对应的简称的值

        abb_pop.loc[abb_pop['state'].isnull()]['state/region']
        

      • c.对简称进行去重

        abb_pop.loc[abb_pop['state'].isnull()]['state/region'].unique()
        

    • 6.为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN

      • 结论一 :只有PR,和 USA对应的全称为空 PR : PUERTO RICO

      • 结论二 :state这一列中的空值有为两种分类,一种是PR 简称对应的空,一种是USA简称对应的空

      • a.先将两种不同分类的空定位到(定位的条件应该是PR或者USA)

        • 将PR所对应的行数据找出

          abb_pop['state/region'] == 'PR'
          abb_pop.loc[abb_pop['state/region'] == 'PR']
          

        • PR类的空对应的行索引

          indexs = abb_pop.loc[abb_pop['state/region'] == 'PR'].index
          

      • b.给每一种分类的空进行指定形式的赋值

        abb_pop.loc[indexs,'state'] = 'PUERTO RICO'
        
        abb_pop['state/region'] == 'USA'
        abb_pop.loc[abb_pop['state/region'] == 'USA']
        #USA类的空对应的行索引
        indexs = abb_pop.loc[abb_pop['state/region'] == 'USA'].index
        #给每一种分类的空进行指定形式的赋值
        abb_pop.loc[indexs,'state'] = 'United States'
        
    • 7.合并各州面积数据areas

      abb_pop_area = pd.merge(abb_pop,area,how='outer')
      

    • 8.我们会发现area(sq.mi)这一列有缺失数据,找出是哪些行

      abb_pop_area['area (sq. mi)'].isnull()
      abb_pop_area.loc[abb_pop_area['area (sq. mi)'].isnull()]
      indexs = abb_pop_area.loc[abb_pop_area['area (sq. mi)'].isnull()].index
      

    • 9.去除含有缺失数据的行

      abb_pop_area.drop(labels=indexs,axis=0,inplace=True)
      

    • 10.找出2010年的全民人口数据

      df_2010 = abb_pop_area.query('year==2010 & ages=="total"')
      df_2010.head(5)
      

    • 11.计算各州的人口密度

      abb_pop_area['population']/abb_pop_area['area (sq. mi)']
      abb_pop_area['midu'] = abb_pop_area['population']/abb_pop_area['area (sq. mi)']
      abb_pop_area.head(5)
      

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

      abb_pop_area.sort_values(by='midu',axis=0,ascending=False)
      

     

6.6美国2012年总统候选人政治献金数据分析

cand_nm(候选人姓名),contbr_nm(捐赠者姓名),contbr_city,contbr_st,contbr_zip,contbr_employer,contbr_occupation(捐赠者的职业),contb_receipt_amt(捐赠金额),contb_receipt_dt(捐赠日期)

 1.读取文件usa_election.txt
 2.查看文件样式及基本信息
 3.【知识点】使用map函数+字典,新建一列各个候选人所在党派party
 4.使用np.unique()函数查看colums:party这一列中有哪些元素
 5.使用value_counts()函数,统计party列中各个元素出现次数,value_counts()是Series中的,无参,返回一个带有每个元素出现次数的Series
 6.【知识点】使用groupby()函数,查看各个党派收到的政治献金总数contb_receipt_amt
 7. 将表中日期格式转换为'yyyy-mm-dd'。日期格式,通过函数加map方式进行转换
 8.得到每天各政党所收政治献金数目。  考察知识点:groupby(多个字段)
 9.查看老兵(捐献者职业)DISABLED VETERAN主要支持谁  :查看老兵们捐赠给谁的钱最多
 10.找出各个候选人的捐赠者中,捐赠金额最大的人的职业以及捐献额  .通过query("查询条件来查找捐献人职业")
  • 包的导入

    import numpy as np
    import pandas as pd
    from pandas import DataFrame,Series
    

    方便大家操作,将月份和参选人以及所在政党进行定义

    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'           
     }
    
  • 1.读取文件usa_election.txt

  • 2.查看文件样式及基本信息

    df = pd.read_csv('./data/usa_election.txt')
    df.head()
    

  • 3.【知识点】使用map函数+字典,新建一列各个候选人所在党派party

    df['party'] = df['cand_nm'].map(parties)
    df.head()
    

  • 4.使用np.unique()函数查看colums:party这一列中有哪些元素

    df['party'].unique()
    

  • 5.使用value_counts()函数,统计party列中各个元素出现次数,value_counts()是Series中的,无参,返回一个带有每个元素出现次数的Series

    df['party'].value_counts()
    

  • 6.【知识点】使用groupby()函数,查看各个党派收到的政治献金总数contb_receipt_amt

    df.groupby(by='party',axis=0)['contb_receipt_amt'].sum()
    

  • 7.查看具体每天各个党派收到的政治献金总数contb_receipt_amt 。使用groupby([多个分组参数])

    df.groupby(by=['contb_receipt_dt','party'])['contb_receipt_amt'].sum()
    

  • 8.将表中日期格式转换为'yyyy-mm-dd'。日期格式,通过函数加map方式进行转换

    def transformDate(d):
        day,month,year = d.split("-")
        month = months[month]
        return '20'+year+'-'+str(month)+'-'+day
    
    df['contb_receipt_dt'].map(transformDate)
    df['contb_receipt_dt'] = df['contb_receipt_dt'].map(transformDate)
    df.head(5)
    

  • 9.查看老兵(捐献者职业)DISABLED VETERAN主要支持谁 :查看老兵们捐赠给谁的钱最多

    #将老兵对应的行数据取出
    df['contbr_occupation'] == 'DISABLED VETERAN'
    old_bing_df = df.loc[df['contbr_occupation'] == 'DISABLED VETERAN']
    old_bing_df.groupby(by='cand_nm')['contb_receipt_amt'].sum()
    

  • 10.找出各个候选人的捐赠者中,捐赠金额最大的人的职业以及捐献额 .通过query("查询条件来查找捐献人职业")

    max_amt = df.groupby(by='cand_nm')['contb_receipt_amt'].max()
    max_amt
    

    for i in range(max_amt.size):
        max_money = max_amt[i]
        display(df.query('contb_receipt_amt =='+str(max_money)))
    

posted @ 2019-09-10 16:22  Primrose  阅读(872)  评论(0编辑  收藏  举报