zoukankan      html  css  js  c++  java
  • Python模块-pandas

    数据分析虽说很多时候需要对业务和数据的理解,但其实大部分时候对数据的操作是相似(即使使用不同的工具,如Excel、Python、R等),像是数据清洗、表格结构修改、字段切分、分组计算等等。下面是使用Python中的Pandas包对数据分析常用操作的笔记。

    数据读取

    pandas读取文件后的数据集是一个DataFrame对象,该对象的每个列是一个Series对象

    # pandas可读取很多文件格式
    # 但一般读取数据的文件格式为:csv 和 excel
    import pandas as pd
    df = pd.read_csv("iris.csv",  
                     sep=',',
                     names=["A","B","C","D"],
                     nrows=2,  # 只要前两行的数据
                     encoding='utf-8'
                    )
    df = pd.read_excel("iris.xlsx",
                       sheetname='XXXX',
                       header=0,  # 指定第一行为表头
                       index_col=0,  # 指定第一列为索引
                       usecols = [0, 2]  # 只要第一和三列的数据
                      )
    
    # 数据库读取
    import pymysql # MySQL
    import pymssql # SQLserver
    
    conn = pymssql.connect(host='XXX.XX.XX.XX', user='username', password='123', database='DB')
    OS = pd.read_sql("SELECT * FROM [KF_SZ].[dbo].[OSdepartrelation]",conn)
    conn.close()
    

    数据探索

    # 查看数据量和特征量
    df.shape
    >>> (68630, 14)
    
    # 查看数据集的头5行
    df.head()
    
    # 查看数据集的尾5行
    df.tail()
    
    # 查看行名
    df.index
    >>> RangeIndex(start=0, stop=68630, step=1)
    
    # 查看列名
    df.columns
    >>> Index(['行号', '仓库', '货号', '条码', '商品名称'], dtype='object')
    
    # 几乎用不上吧
    df.values 
    
    # 查看数据格式
    df.dtypes
    >>> 行号        int64
        仓库       object
        货号        int64
        条码       object
    
    # 计数:每个特征(列)的非空数量
    df.count()
    >>> 商品名称    68630
        规格       6340
        单位      67719
        库存数量    68630
    
    # 计数:对单个列(Series)的频数统计
    df['仓库'].value_counts()
    >>> 公司总部总仓库       2016
        佛山南海万科店        938
        深圳宝安兴业店        928
        深圳宝安百年店        907
    
    # 返回唯一值的数组
    df['区域'].unique()
    >>> array(['深圳', '东莞', '广州', '佛山', '江门', '成都', '四川'], dtype=object)    
    
    # 统计描述:可以对整个数据集(DataFrame),也可以对单个列(Series)
    df.describe()
    df['库存数量'].describe()
    >>> count    68630.000000
        mean        19.545230
        std        248.819321
        min      -1600.000000
        25%          2.000000
        50%          5.000000
        75%         14.000000
        max      38080.000000
        Name: 库存数量, dtype: float64
                       
    # 小技巧
    df.describe().astype(np.int64).T
    

    数据清洗

    数据清洗

    # 单列字段清洗-去空格
    df['商品名称'] = df['商品名称'].map(lambda s : s.strip())
    df['A']=df['A'].map(str.strip)   # 去除两边空格
    df['A']=df['A'].map(str.lstrip)  # 去除左边空格
    df['A']=df['A'].map(str.rstrip)  # 去除右边空格
    df['A']=df['A'].map(str.upper)   # 转大写
    df['A']=df['A'].map(str.lower)   # 转小写
    df['A']=df['A'].map(str.title)   # 首字母大写
    
    # 字段切分,并创建新特征
    df.loc[:,"区域"] = df['仓库'].map(lambda s:s[0:2])
    

    类型转换

    # 转换某特征(列)的数据格式
    df['行号'] = df['行号'].astype(float)  
    
    # 转化时间格式
    df['time']=pd.to_datetime(df['time'])
    

    缺失值

    • 缺失值查看
    # 缺失值判断(在原数据对象以T/F替换)
    df.isnull()
    df.notnull()
    df['A'].isnull()
    
    • 缺失值统计
    # 缺失值计数方法
    # 方法一
    df['A'].isnull().value_counts()
    >>> True     68629
        False        1
        Name: A, dtype: int64
    # 方法二
    df['A'].isnull().sum()
    >>> 68629
    df.isnull().sum()
    >>> 仓库          0
        货号          0
        条码          2
        规格      62290
    
    • 缺失值删除
    # 默认axi=0,how='any': 按行,任意一行有NaN就整列丢弃
    df.dropna()
    df.dropna(axis=1)
    
    # 一行中全部为NaN的,才丢弃
    df.driopna(how='all')
    
    # 保留至少3个非空值的行:一行中有3个值是非空的就保留
    df.dropna(thresh=3)
    
    • 缺失值填充
    # 整个数据集填充
    df.fillna(0)
    
    # 有针对性的填充
    df.fillna({'性别':'男', '年龄':30})
    

    重复值

    # 返回布尔向量、矩阵
    df['A'].duplicated()
    df.duplicated()
    
    # 整个实例一模一样才删除,默认保留第一行
    df.drop_duplicates()
    
    # 保留k1列中的唯一值的行,默认保留第一行
    df.drop_duplicates(subset=["k1"])
    
    # 保留 k1和k2 组合的唯一值的行,take_last=True 保留最后一行
    df.drop_duplicates(subset=["k1","k2"], take_last=True)
    

    值替换

    # 一对一替换
    # 将df的A列中 -999 全部替换成空值
    df["A"].replace(-999, np.nan)
    
    # 多对一替换
    # -999和1000 均替换成空值
    obj.replace([-999,1000],  np.nan)
    
    # 多对 一对一替换
    # -999替换成空值,1000替换成0
    obj.replace([-999,1000],  [np.nan, 0])
    # 同上,写法不同,更清晰
    obj.replace({-999:np.nan, 1000:0})
    
    # 有趣的写法
    dataset_raw.loc[dataset_raw['workclass'] == 'Without-pay', 'workclass'] = 'Not Working'
    

    修改表结构

    一般数据分析需要修改表结构都是在列上动手脚,注意操作有以下几种

    新增列

    # 方式一
    df['test'] = 0
    
    # 方式二
    df.loc[:,"区域"] = df['仓库'].map(lambda s:s[0:2])
    
    # 方式三
    df.loc[:,"is_bonus"]=1
    df.loc[df['remarks']=='无奖金', 'is_bonus'] = 0
    
    # 方式四
    # 需求:创建一个新变量test2 
    # 1.petal_length>2 and petal_width>0.3 = 1 
    # 2.sepeal_length>6 and sepal_width>3 = 2 3.其他 = 0
    df.loc[(df['petal_length']>2)&(df['petal_width']>0.3), 'test2'] = 1
    df.loc[(df['sepal_length']>6)&(df['sepal_width']>3), 'test2'] = 2
    

    删除列

    # 丢弃指定的特征(列)
    df.drop(['行号','条码'],
            axis=1,
            inplace=True)
    

    删除行

    # 删除特色的行用得少,一般使用切片
    df.drop(index=['no1','no2'],
            axis=0,
            inplace=True)
    
    df.drop(df.index[[0,1]],
            axis=0,
            inplace=True)
    

    修改列名

    df.rename(columns = {'年':'compute_year',
                         '月/季度':'compute_month', 
                         '员工编号':'code', 
                         '员工姓名':'name', 
                         '职位':'position', 
                         '体系':'system_name',
                         '运营单位':'op_unit_name', 
                         '区域':'sub_area_name',
                         '部门名称':'dept_name', 
                         '员工所属小组': 'sub_dept_name'},
              inplace=True)
    

    数据分组(数值变量)

    # cut()数据分组,以连续值变量分组创建新特征
    bins = [0, 5, 10, 15, 20]  # 切分的边界
    group_names = ['A', 'B', 'C', 'D']  # 每组的标签名
    df['new'] = pd.cut(df['old'], bins, labels=group_names) # new就是分组新特征
    
    # qcut只要指定切分个数即可
    df.qcut(df['年龄'],4)
    

    数据分列(分类变量)

    这个操作和Excel中的分列功能很像,在原始数据表中grade列中包含了两个层级的用户等级信息,现在我们通过数据分列将分级信息进行拆分。数据分列操作使用的是split函数,下面是具体的代码和分列后的结果。

    grade_split = pd.DataFrame((x.split('-') for x in loandata.grade),
                               index=loandata.index,
                               columns=['grade','sub_grade'])
    

    完成数据分列操作后,使用merge函数将数据匹配会原始数据表,这个操作类似Excel中的Vlookup函数的功能。通过匹配原始数据表中包括了分列后的等级信息

    loandata=pd.merge(loandata,grade_split,right_index=True, left_index=True)
    

    设置索引

    # 将列转化为索引
    # 将columns中的其中两列:race和sex设置索引,race为一级,sex为二级
    # inplace=True 在原数据集上修改的
    # 默认情况下,设置成索引的列会从DataFrame中移除, drop=False将其保留下来
    adult.set_index(['race','sex'], inplace = True) 
    
    # 取消列索引设置,并自动填充索引
    adult.reset_index(level=None, drop=Fasle, inplace=False)
    
    # 索引重塑
    df.stack()
    df.unstack()
    

    排序

    df.b(by=['code'], ascending=False, na_position='first')
    df.sort_values(by=['code', 'name'], ascending=False, na_position='first')
    # 缺失值NaN默认是排在最后后的,na_position='first'设置为排在最前面
    

    数据筛选/切片

    • []
    • isin
    • loc
    • iloc
    • ix
    • contains
    # []只能对 行(row/index) 切片,前闭后开
    df[0:3]
    df[:4]
    df[4:]
    
    # where布尔查找,建立在[]基础之上
    df[df["A"]>7]
    # 并
    df.loc[(df['petal_length']>2)&(df['petal_width']>0.3)] 
    # 或
    df.loc[(df['petal_length']>2)|(df['petal_width']>0.3)] 
    
    # isin()
    # 返回布尔值
    df["A"].isin([1,2,3])
    df.loc[df['sepal_length'].isin([5.8,5.1])]
    
    # loc :根据名称Label切片
    # df.loc[A,B] A是行范围,B是列范围
    df.loc[:, ['petal_length','petal_width']]
    df.loc[1:4, ['petal_length','petal_width']]
    df.loc[['no1','no2'], ['petal_length','petal_width']]
    
    # iloc:切位置,以序列号去切
    df.iloc[1:4,:]
    
    # ix:混切
    # 名称和位置混切,但效率低,少用
    df1.ix[0:3,['sepal_length','petal_width']]
    
    # contains()模糊匹配
    # 使用DataFrame模糊筛选数据(类似SQL中的LIKE)
    # 使用正则表达式进行模糊匹配,*匹配0或无限次,?匹配0或1次
    df_obj[df_obj['套餐'].str.contains(r'.*?语音CDMA.*')] 
    # 下面两句效果一致
    df[df['商品名称'].str.contains("四件套")]
    df[df['商品名称'].str.contains(r".*四件套.*")]
    

    正则表达式

    多表拼接

    merge 合并

    • pandas.merge可根据一个或多个键将不同DataFrame中的行合并起来

      # 在未指定连接键的情况下,merge会将重叠列的列名当做键
      pd.merge(left, right)
      
      # 指定“on”作为连接键,left和right两个DataFrame必须同时存在“on”列,连接键也可N对N(少用)
      pd.merge(left, right, on="key")
      pd.merge(left, right, on=["key1", "key2"])
      
      # 指定left的连接键为“lkey”,right的连接键为“rkey”
      pd.merge(left,  right,  left_on="lkey",  right_on="rkey")
      
      # suffixes:用于追加到重叠列名的末尾,默认为("_x", "_y")
      pd.merge(left,  right,  on="key",  suffixes=("_left",  "_right"))
      
      # 指定连接方式:“inner”(默认),“left”,“right”,“outer”
      pd.merge(left, right, how="outer")
      
    • 多对多连接产生的是行的笛卡尔积

    • 常用方式:连接方式为“left”,right的连接键要唯一(去除重复值),通过right的数据补全left的数据索引上的合并(可用join代替,而且join更方便)

    • 当DataFrame的连接键位于其索引中,可以使用 left_index=True 和 right_index=True

      # 索引和索引连接
      pd.merge(left,  right,  left_index=True,  right_index=True)
      
      # "key"和索引连接
      pd.merge(left,  right,  left_on="key",  right_index=True)
      
      # 层次化索引
      pd.merge(left,  right,  left_on=["key1", "key2"],  right_index=True)
      

    join 连接

    • DataFrame的join实例方法,是为了方便实现索引合并

      # 用left的索引和right的索引进行merge
      left.join(right)
      
      # 用left的索引和right的“key”进行merge
      left.join(right, on="key")
      
      # 层次化索引
      left.join(right, on=["key1", "key"])
      
      # join可以合并两张以上的表,而merge只能合并两张表
      left.join([right1, right2], how="outer")
      

    concat 轴向连接

    • pandas.concat可以沿着一条轴将多个表对象堆叠到一起:因为模式how模式是“outer”

      # 默认 axis=0 上下拼接,列column重复的会自动合并
      pd.concat([df1, df2], axis=0)
      
      # axis=1 左右拼接,行raw/index重复的会自动合并
      pd.concat([df1, df2], axis=1)
      
      # 忽略df1和df2原来的index,重新给新的DataFrame设置从0开始的index
      pd.concat([df1,df2],  ignore_index=True)
      

    append

    • 使用场景:表头一致的多张表,进行连接(上下连接)

      df1.append(df2).append(df3)
      

    combin_first 数据填补

    • 使用场景:有两张表left和right,一般要求它们的表格结构一致,数据量也一致,使用right的数据去填补left的数据缺漏

    • 如果在同一位置left与right数据不一致,保留left的数据

      df1.combin_first(df2)
      

    数据聚合&分组运算

    groupby

    # 单层分组
    df.groupby('区域')
    # 多层分组
    df.groupby(['A','B'])
    
    # 每个分组记录的计数
    df.groupby('区域').size()
    >>> 区域
    	东莞     7528
    	中山      520
    	佛山     5632
        ...
    	dtype: int64
         
    # 分组数
    len(df.groupby('区域'))
    >>> 7
    

    aggregate

    grouped = df.groupby(['A','B'])
    # 对一个特征一次求得多个统计数
    grouped['age'].agg([np.sum, np.mean, np.std])
    # 对单一属性统计可以改列名
    grouped['age'].agg({"求和":np.sum,"求平均数":np.mean})
    # 对不同属性求不同的统计数
    grouped.agg({'age':np.mean,'fnlwgt':np.sum})
    

    filter

    # filter()
    # 过滤分组计数少于1000的分组,在把分组计数大于1000的分组整合成一个DataFrame返回
    con1 = lambda s : len(s) > 1000
    df1 = grouped.filter(con1)
    # 过滤分组age均值小于30的分组
    con2 = lambda s : s['age'].mean()>30
    df2 = grouped3.filter(con2)
    

    tansformation

    # tansformation()
    # 会返回一个数据集,这个数据集与group具有相同的索引以及大小 相当分组处理后合并
    # 举例说明对数据集进行标准化:
    zscore = lambda s : (s - s.mean())/s.std()
    df = grouped.transform(zscore)
    

    数据透视表

    crosstab

    # crosstab() 一般只用与计数的数据透视表
    pd.crosstab(index= df['A'],
                columns = [df['B'],df['C']],
                margins =True, 
                dropn=True)
    

    pivot/pivot_table

    # Produce 'pivot' table based on 3 columns of this DataFrame.
    # Uses unique values from index / columns and fills with values.
    # 感觉能使用的场景很少,因为不重复
    df.pivot(index, columns, values)
    
    df.pivot_table(values=None, 
                   index=None, 
                   columns=None, 
                   aggfunc='mean', 
                   fill_value=None, 
                   margins=False, 
                   dropna=True, 
                   margins_name='All')
    # 需求: index 是A ,columns 是 B,C, 我要求E的平均数并且有边
    pd.pivot_table(df,
                   values = 'E',
                   index = 'A',
                   columns = ['B','C'],
                   aggfunc = [np.mean,np.sum],
                   margins = True)
    

    时间序列

    时间格式转化

    # 转化时间格式
    df['time']=pd.to_datetime(df['time'])
    

    时间索引操作

    
    

    哑编码

    pd.get_dummies(data, 
                   prefix=None, 
                   prefix_sep='_', 
                   dummy_na=False, 
                   columns=None, 
                   sparse=False, 
                   drop_first=False)
    

    数据导出

    pd.to_csv("XXX.csv",index=False)
    
    from sqlalchemy import create_engine
    engine = create_engine('mssql+pymssql://zxadmin:Zx!@#$8888@172.17.180.113/BS_KF')
    pd.io.sql.to_sql(df,'payroll',engine,if_exists='append',index=False,chunksize=10000)
    

    数据入库

    # pd 1.9以后的版本,除了sqllite,均需要通过sqlalchemy来设置
    from sqlalchemy import create_engine
    engine = create_engine('mssql+pymssql://zxadmin:Zx!@#$8888@172.17.180.113:8000/BS_KF')
    # append:如果表存在,则将数据添加到这个表的后面
    # fail:如果表存在就不操作
    # replace:如果存在表,删了,重建
    pd.io.sql.to_sql(df,'table_name',engine,if_exists='append',index=False,chunksize=10000)
    # 关闭连接
    engine.dispose() 
    

    技巧

    数据集概览

    # 整体概况
    def birdview(data):
        print(data.shape)
        d = {}
        for col in data.columns:
            if len(list(data[col].unique()))<30:
                d[col]= str(list(data[col].unique()))
            else:
                d[col]= "too much"
    
        r = pd.DataFrame(pd.Series(d),columns=['values'])
                .join(pd.DataFrame(data.dtypes,columns=['type']))
                .join(pd.DataFrame(data.count(),columns=['count']))
                .join(pd.DataFrame(data.isnull().sum(),columns=['isnull']))
                
        return r.sort_values(by=['values','type',])
    
    def catview(data):
        print("定性数据概况")
        for c in data.columns:
            print(c)
            print(dict(df[c].value_counts()))
    
    def valueview(data):
        print("定值数据概况")
        return data.describe().T
                .join(pd.DataFrame(data.skew(),columns=['skew']))
                .join(pd.DataFrame(data.kurt(),columns=['kurt']))
    

    长宽表转换

    宽表转换为长表

    # 方法一:先用set_index,再用stack,然后还有rename修改下列名
    df.set_index(['Company','Name'], inplace = True).stack().reset_index()
    
    # 方法二:melt
    df.melt(id_vars=['Company','Name'],
            var_name='Year',
            value_name='Sale')
    

    长表转换为宽表

    df.pivot_table(index=['Company','Name'], columns='Year', values='Sale')
    

    行列互换

    df.T
    
  • 相关阅读:
    [SQL]触发器把自增ID的值赋值给另外一个字段
    [SQL]T-Sql 递归查询(给定节点查所有父节点、所有子节点的方法)
    [二维码开发]二维码开发入门级demo
    [sql]sql函数coalesce返回第一个非空的值
    [编程小技巧]Notepad++中如何实现文本对比功能?
    [ExcelHome]VLOOKUP的别样用法
    [ExcelHome]15个常用的Excel函数公式,拿来即用
    [ExcelHome]学习Excel的网站
    Permutations
    Remove Duplicates from Sorted List II
  • 原文地址:https://www.cnblogs.com/stream886/p/10474661.html
Copyright © 2011-2022 走看看