Python数据分析常用API整理

作者: shohokuooo | 来源:发表于2017-08-01 16:19 被阅读215次

    整理归纳在Python中使用对数据处理的常用方法,包括与HDFS文件的读写,主要是怕用的时候记不住,容易搞混,再搜也不爽,好记性不如烂笔头,写下来自己用的时候方便看,而且写一遍也加深印象。
    随查随用随更新

    Numpy

    ndarray

    ndarr1 = np.array([ [1, 2, 3], [4, 5, 6] ])
    shape 大小和形状
    dtype 数据类型
    astype 显式的转换类型
    不同大小的ndarray也可以运算,称之为广播,比如arr * 2
    一维:用[x]进行索引,用[x:y]进行切片,都是原始数组的视图
    多维:[x][y]或者[x,y]索引,[x1:x2, y1:y2]切片
    布尔型可以直接做索引

    按轴进行布尔类型list的索引,或者对每个元素进行单个布尔索引,比如data1[data1 > 0] = 0

    花式索引行和列

    arr[ [行1, 行i] ][ :, [列1, 列i] ] 或者
    arr[ np.ix_( [行1, 行i], [列1, 列i] ) ]
    而且花式索引总是复制数据到新的数组中,不是切片那种原始数组的视图

    arr.T 转置
    通用函数

    np.sqrt(arr) arr的开平方
    np.exp(arr) arr的e的x次方
    np.abs(arr) arr的绝对值
    np.square(arr) arr的平方
    np.log(arr) ln(arr)
    np.log10(arr) log10(arr)
    np.isnan arr的各个元素是否为NaN的bool数组
    np.add(arr1, arr2) arr1 + arr2
    np.subtract(arr1, arr2) arr1 - arr2

    三元表达式
    np.where(cond, xarr, yarr) 等价为 xarr if cond else yarr
    统计

    arr.sum(axis=?) 按照轴的方向求和
    arr.mean 按照轴的方向求平均值
    arr.min()和max() 最大和最小值
    arr.argmin()和argmax() 最大和最小值的索引
    arr.cumsum() 所有元素的累计和
    arr.cumprod() 所有元素的累计积
    排序
    np.sort(arr)和arr.sort(),前者是顶级方法,返回对arr排序后的副本;后者则是直接对arr排序。

    线性代数
    包括矩阵的点乘,矩阵分解以及行列式等等。
    点乘:xarr.dot(yarr)等价于np.dot(xarr, yarr)
    numpy.linalg中有一组标准的矩阵分解运算以及诸如求逆和行列式之类。比如如下部分:

    diag([一维数组]) 对角矩阵,对角线是输入的一维数组
    dot 点乘
    det 计算矩阵的行列式
    inv 计算矩阵的逆
    qr 计算QR分解
    svd 计算奇异值分解(SVD)

    Pandas

    (官网)https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html
    官网Pandas的API汇总
    官网10分钟对Pandas的简介

    Series

    可以把Series看成是一个有序的定长字典。
    ser = Series([1, 2, 3, 4], index=['d', 'b', 'a', 'c'])
    经常存在与DataFrame的行与列中。
    也可以直接从字典类型的对象中构建。
    idx_val_map = {'d':1, 'b':2, 'a':3, 'c':4}
    ser = Series(idx_val_map, name='值的名称')
    ser.index.name = '索引的名称'
    ser['a']进行索引
    再进一步,比如对于二维的DataFrame,取其中一列出来,就是Series,它的name就是这一列的名字,它的index就是DataFrame的index,index的name就是DataFrame中作为index的那一列的名字。

    DataFrame

    DataFrame的索引是不可更改的。可以添加和删除,但是不能修改。

    • 构造DataFrame
      1.由二维ndarray构造,可以给出行标和列标
      result1 = pd.DataFrame([[1, 0.7], [0, 0.7]], index=pd.Index([135, 136], name='Number'), columns=['Gender', 'Prob'])
      
      2.由字典构成,外层字典key是列标,内层字典是行标
      需要注意的是字典构成的df,需要指定column的顺序,否则默认会按照列的字符串名排序
    predict_df = pd.DataFrame(data={'svc_y': svc_y, 'dnn_y': dnn_y, 'xgb_y': xgb_y, 'rf_y': rf_y}, columns=['svc_y', 'dnn_y', 'xgb_y' ,'rf_y'])
    

    3.由另一个DataFrame构成
    有时候会有一种需求是从已经有的DataFrame中创建一个空的Dataframe但是使用的是原来这个Dataframe的结构。

    copy_df = pd.DataFrame.from_items([(name, pd.Series(data=None, dtype=series.dtype)) 
                                        for name, series in original_df.iteritems()])
    
    • 添加列

      frame['new-col'] = value
      
    • 添加行

      s = pd.Series({'Col1':'Value1', 'Col2': 'Value2', 'Col3': Value3})  # 构造一行新数据
      frame.append(s)
      
    • 删除列

      del frame['col-name']
      
    • 删除行

      # 因为DataFrame是列索引的(在frame.items()返回值中可以看出来)所以del只能删除列,删除行需要用到drop方法
      frame.drop(frame.index[[1,3]])
      
    • 索引方式
      列索引:frame['col_name']或者frame.col_name
      行索引:frame.ix['row_name']
      点索引:frame.at[行,列] 或者frame.iat[行i,列i],只能索引具体的元素,不能切片
      用整数位置索引frame.iloc[index(列表), col-index(列表)]
      ix[行, 列]和iloc[行, 列]都可同时索引行与列,区别在于ix用的是名字(当DataFrame的index没有设置时,退化成iloc),iloc用的是整数位置
      loc: works on labels in the index.
      iloc: works on the positions in the index (so it only takes integers).
      ix: usually tries to behave like loc but falls back to behaving like iloc if the label is not in the index.

      • 总结
        ['col-name']——是对列的索引
        [ ['col-name1', 'col-name_i'] ]——两个[]是对多个列的索引
        [bool类型list]或者[i:j]——是对行的切片索引
        ix[行,列]——支持对行和列同时索引和切片(loc和iloc参考上面)NOTE:ix操作如果有左值,那么就默认会copy,如果没有左值那么就是对原始Frame进行操作,而loc和iloc默认都是对原始Frame的操作,所以推荐使用loc,如果需要复制,可以显式的调用Frame.copy(). 不过仍要注意的是frame2 = frame1.loc[a:d, :]确实不是复制是对原frame1的切片,但是frame1.loc[ [a, b, c, d], :]则是复制不是切片了。
        at[行,列]和iat[i,j]——是定位到元素
        所以对列的bool类型list切片应该用ix[:,bool_list],然而对行的bool类型list切片可以直接[bool_list]
    • 基本功能

      • 重新索引
        reindex,对索引重新排序,新加的使用缺失值填充。

      • 丢弃指定轴上的项
        frame.drop(['name'], axis=?)

      • 切片
        frame[:2] 这个是直接按行切片,和常识有点不太一样,但是方便实际操作。
        frame[ ['列1', '列i'] ],这个是按列切片

      • 过滤
        按照某一列的值过滤:frame[ frame['列'] > 5 ]
        对于bool类型的list,除了上面的方法,也可以frame.loc[bool_list_X, bool_list_Y]进行过滤。

      • 算术运算
        frame1 + frame2 或者 frame1.add(frame2, fill_value=0)
        sub做减法 div是除法 mul是乘法

      • 函数应用和映射
        Numpy的ufuncs也可用于操作pandas对象

        np.abs(frame)

        还可以自定义函数(列或行的):

        f = lambda x: x.max() - x.min()
        frame.apply(f, axis=?)

        对元素的函数

        format = lambda x: '%.2f' % x
        frame.applymap(format)

        featQuant = sampleDF_feat.quantile(0.999) # 获得0.999的分位数
        frameFeatUnderQuant = sampleDF_feat.where(sampleDF_feat <= featQuant, other=0) # 把异常高的数值排除掉

        总的来说,DataFrame可以用的是apply和applymap,Series可以用的是map:

        apply:是对DataFrame的具体行或者列进行整体操作。比如可以取最大最小值
        applymap:是对DataFrame的具体每个元素进行操作。
        map:也是对每个元素进行操作,和applymap类似。

      • 排序
        frame.sort_index(by='name', axis=?, ascending=True)

    • 汇总和计算描述

      frame.sum(axis=?, skipna=True) 求和
      frame.mean() 平均值
      frame.count()
      frame.min、max
      frame.argmin、argmax 整数索引位置
      frame.idmin、idmax 名字ID索引位置
      frame.quantile() 计算样本的分位数(0到1),比如frame['col_name'].quantile([q/10 for q in range(1, 11, 1)])
      frame.describe() # 描述各个列的详细统计信息
      frame.info() # 描述各个列是否有缺失值和dtype

    • 处理缺失数据

      frame.dropna() 丢弃NaN,可以给出阈值进行调节容忍度
      df.fillna( {'列1': 值1, '列i': 值i}, inplace=True ) 默认返回一个新的对象
      frame.isnull() 返回与frame一样大小的布尔值对象(值为NaN的为True,否则为False)

    • 其他常用

      # 去重
      df.duplicated(keep='first')  # 这个会返回列的值重复与否的布尔值,默认对于重复值的第一个为False,其他重复的为True
      # 得到这个布尔后可以再进行切片去重,不过还有更便捷的方法:
      df['某列'].drop_duplicates(keep='first', inplace=True)  # 这样直接得到去重后的结果。
      
    • 从文件中读取
      frame = pd.read_csv('file.csv', names=col_names, index_col='col_index')
      除了读取本地文件还可以读取HDFS文件:

      首先需要安装需要的包:pip install hdfs 官网文档
      然后代码中:

      from hdfs import Client
      from hdfs import HdfsError
      
      client = Client('http://name_node.url:50070')  # 输入要链接的NameNode地址。如果是高可用的模式,会有多个name node,那么有个比较笨的方法就是挨个试,看看那个可用(也就是处于active状态)就用哪个。
      
      print(client.list('/'))  # 可以在这里添加try操作,catch到异常后去尝试下一个name node的链接。
      
      try:
          with client.read('path/file.csv') as hdfs_in_fs:
              predictDF = pd.read_csv(hdfs_in_fs, names=predict_cols, index_col='Number')
      except HdfsError as e:
          print(e)
      
    • 将Frame写入文件
      frame.to_csv(path_or_buf='path/file', index=True, header=False, sep='|')
      写入HDFS文件会有些麻烦,一是写的时候需要权限,把要写入的目录设置为hdfs dfs -chmod -R 777 write_Dir;二是写入文件会遇到TypeError: a bytes-like object is required, not 'str',因为不像普通的文件可以在open的时候设置mode参数,所以还需要做如下操作:

      from hdfs import Client
      from hdfs import HdfsError
      
      client = Client('http://name_node.url:50070')  # 输入要链接的NameNode地址。如果是高可用的模式,会有多个name node,那么有个比较笨的方法就是挨个试,看看那个可用(也就是处于active状态)就用哪个。
      
      print(client.list('/'))  # 可以在这里添加try操作,catch到异常后去尝试下一个name node的链接。
      
      try:
          with client.write('path/file' overwrite=True, encoding='utf-8') as hdfs_out_fs:  # 需要设置encoding不然遇到上面说的TypeError
              predictDF[['Gender', 'Prob']].to_csv(path_or_buf=hdfs_out_fs, index=True, header=False, sep='|')
      except HdfsError as e:
          print(e)
      
    • 另外一种读写HDFS文件的方法
      上面的代码确实可以读写HDFS文件,不过需要修改权限,这会出现下面情况:

      可以看到为了允许读写,上级目录已经将权限更改为全部可读写执行了,而且新创建的文件夹和文件都是用户dr.who

      这会给后续操作带来一定的麻烦,比如yarn用户在程序中对这个文件无法修改。因为只有读权限。
      不过还有一个API可以在python中使用,如果你的HDFS配置支持非安全的HttpFS的话。

      Client API介绍

      上面的使用Client的API是用的WebHDFS。连接的时候需要指定namenode,而在高可用的模式情况下,可能要多试几次才知道当前哪个node处于active状态。为了避免这两个问题,接下来展示另外一个API InsecureClient来实现。在接下来的代码中,使用的是HttpFS方式来读写HDFS

      from hdfs import InsecureClient
      
      client = InsecureClient('http://HttpFS_node.url:14000', user='yarn')  # 使用HttpFS所配置的角色主机域名及REST 端口
      
      print(client.list('/'))  # 无需像之前一样多次尝试当前输入的namenode是否可用
      
      with client.read('path/in_file') as hdfs_in_fs:
          with client.write('path/out_file', overwrite=True, encoding='utf-8') as hdfs_out_fs:
              sampleDF = pd.read_csv(hdfs_in_fs, names=, index_col=)
              sampleDF.to_csv(path_or_buf=hdfs_out_fs, index=True, header=False, sep='|')
      

      这个API的好处是:1、不需要修改权限,由参数的指定用户保证权限没问题。2、新写入的文件权限也无问题。3、可以支持远程读写,无需在集群上执行,在本地PC上运行即可。4、无需知道当前active的namenode是哪个,可以通过HttpFS主机直接连接。

      新建的文件都是用户yarn的
    • 合并数据集

      • pandas.merge
        根据一个或多个键将不同的DataFrame中的行连接起来。类似SQL的关系型数据库的连接操作
        简单说就是将多个DataFrame按照指定的各自的列以某种方式(inner,left,right,outer)组合起来。
        除了pd.merge还有frame_left.join(frame_right)这个方式
      • pandas.concat
        沿着一条轴将多个对象堆叠在一起
        比如将两个frame的行数据堆叠起来。
        frame_total = pd.concat([frame1, framei], axis=?, keys=['col1_name', 'coli_name'])
      • 举栗
        合并Series到Dataframe中:
        purchase_1 = pd.Series({'Name': 'Chris',
                            'Item Purchased': 'Dog Food',
                            'Cost': 22.50})
        purchase_2 = pd.Series({'Name': 'Kevyn',
                            'Item Purchased': 'Kitty Litter',
                            'Cost': 2.50})
        purchase_3 = pd.Series({'Name': 'Vinod',
                            'Item Purchased': 'Bird Seed',
                            'Cost': 5.00})
        df = pd.DataFrame([purchase_1, purchase_2, purchase_3], index=['Store 1', 'Store 1', 'Store 2'])
        
        s = pd.Series({'Name':'Kevyn', 'Item Purchased': 'Kitty Food', 'Cost': 3.00})
        s.name = 'Store 2'
        
        # 合并s到df中
        # 方法1,使用concat函数
        df = pd.concat([df, s.to_frame().T])
        # 方法2,使用append
        df = df.append(s)
        
    • 打印DataFrame
      打印DataFrame非常简单直接print就可以了,但是Pandas对于显示的行数、列数、宽度和长度都有默认限制,如果不期望看到...这样的省略号,或者不期望换行,那么可以如下设置:

      pd.set_option('display.height',1000)  # 把1000换成None即为无限制,下面均是如此。
      pd.set_option('display.max_rows',500)
      pd.set_option('display.max_columns',500)
      pd.set_option('display.width',1000)
      

      上面的设置完之后会对后面的代码全部做这个配置处理,如果想在代码中动态的改变,还可以这么写:

      with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.width', None, 'display.height', None):
          logging.info('输出打印DataFrame:\n{}'.format(data_frame))
      

      这样在需要长显示的时候套上with就可以了,不需要的地方继续使用pandas的默认设置。

    Matplotlib

    常用作图方法

    import matplotlib.pyplot as plt
    %matplotlib inline  # 在ipynb上显示图片
    
    plt.plot([4, 3, 2, 1])  # 作图代码
    plt.show()  # 在python运行程序时显示
    
    # 启动ipython作图时可以: ipython --pylab,这样就会自动import matplotlib.pyplot as plt而且不用show()就可以输出图表。
    plt.plot([4, 3, 2, 1])  # 使用ipython --pylab后直接显示图图表
    

    直接用数据作图

    • 对于numpy的数组数据作图:
    fig = plt.figure()
    ax1 = fig.add_subplot(2, 2, 1)
    ax2 = fig.add_subplot(2, 2, 2)
    ax3 = fig.add_subplot(2, 2, 3)
    plt.plot([1.5, 3.5, -2, 1.6])  # 默认对最后创建的subplot作图
    import numpy as np
    from numpy.random import randn
    _ = ax1.hist(randn(100), bins=20, color='k', alpha=0.3)  # 直方图
    ax2.scatter(np.arange(30), np.arange(30) + 3 * randn(30))  # 散列图
    
    默认画图,直方图和散列图
    • 强调数据点
    plt.plot(randn(30).cumsum(), 'ko--')  # 等价于下面语句
    plt.plot(randn(30).cumsum(), color='k', linestyle='dashed', marker='o')
    
    强调数据点位置
    • 图中坐标和标题设置
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(randn(1000).cumsum())
    ticks = ax.set_xticks([0, 250, 500, 750, 1000])  # 设置X轴的刻度
    labels = ax.set_xticklabels(['one', 'two', 'three', 'four', 'five'], rotation=30, fontsize='small')  # 刻度的标签
    ax.set_title('My first matplotlib plot')  # 图的标题
    ax.set_xlabel('Stages')  # X轴的名称
    
    设置坐标轴的信息和图标题
    • 添加图例
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(randn(100).cumsum(), 'k', label='one')  # 创建图例
    ax.plot(randn(100).cumsum(), 'g--', label='two')
    ax.plot(randn(100).cumsum(), 'r.', label='three')
    ax.legend(loc='best')  # 把上面设置的图例(legend)创建生效
    
    图例
    • 保存图表到文件
    plt.savefig('figpath.svg')
    plt.savefig('figpath.png', dpi=400, bbox_inches='tight')
    

    Pandas的绘图函数

    • Series做柱状图
    import pandas as pd
    from pandas import Series, DataFrame
    fig, axes = plt.subplots(nrows=2, ncols=1)  # 获得subplot集合
    data = Series(np.random.rand(16), index=list('abcdefghijklmnop'))
    data.plot(kind='bar', ax=axes[0], color='k', alpha=0.7)  # 竖向柱状图,不设置kind默认是线形图
    data.plot(kind='barh', ax=axes[1], color='k', alpha=0.7)  # 横向柱状图
    
    Series柱状图
    • DataFrame做柱状图
    df = DataFrame(np.random.rand(6, 4),
                  index=['one', 'two', 'three', 'four', 'five', 'six'],
                  columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'))
    print(df)
    df.plot(kind='bar')
    

    df数据打印:
    Genus A B C D
    one 0.017426 0.964258 0.479931 0.636357

    two 0.020693 0.979753 0.846889 0.436802
    three 0.650068 0.608675 0.964375 0.866141
    four 0.523848 0.610598 0.296204 0.879183
    five 0.419329 0.023081 0.442044 0.842727
    six 0.926948 0.454734 0.436056 0.970364

    DataFrame的柱状图
    • 直方图和密度图
    comp1 = np.random.normal(0, 1, size=200)  # N(0, 1)
    comp2 = np.random.normal(10, 2, size=200) # N(10, 4)
    values = Series(np.concatenate([comp1, comp2]))  # 合并为一个Series
    values.hist(bins=100, alpha=0.3, color = 'k', normed=True)  # 直方图
    values.plot(kind='kde', style='k--')  # 密度图(kde表示标准混合正态分布)
    
    直方图和密度图
    • 散布图
    plt.scatter(trans_data['m1'], trans_data['unemp'])  # 散布图
    plt.title('Changes in log %s vs. log %s' % ('m1', 'unemp'))
    
    散布图
    pd.plotting.scatter_matrix(trans_data, diagonal='kde', color='k', alpha=0.3)  # 散布图矩阵
    
    散布图矩阵

    相关文章

      网友评论

        本文标题:Python数据分析常用API整理

        本文链接:https://www.haomeiwen.com/subject/ttdmkxtx.html