本文为您介绍如何创建和操作DataFrame对象,以及使用Dataframe完成基本的数据处理。

DataFrame对象操作

本文将以movielens 100K进行举例。现在已经有了三张表,分别是pyodps_ml_100k_movies(电影相关的数据)、pyodps_ml_100k_users(用户相关的数据)、pyodps_ml_100k_ratings(评分有关的数据)。

  1. 当运行环境没有提供ODPS对象时,您需要自己创建该对象。
    from odps import ODPS
    o = ODPS('**your-access-id**', '**your-secret-access-key**',
             project='**your-project**', endpoint='**your-end-point**')
  2. 创建一个DataFrame对象非常容易,只需传入Table对象即可。
    from odps.df import DataFrame
    users = DataFrame(o.get_table('pyodps_ml_100k_users'))
  3. 您可以通过dtypes属性查看这个DataFrame的字段及字段类型。
    users.dtypes
    odps.Schema {
      user_id             int64
      age                 int64
      sex                 string
      occupation          string
      zip_code            string
    }
  4. 通过head方法,您可以取前N条数据并进行快速预览。
    users.head(10)
       user_id  age  sex     occupation  zip_code
    0        1   24    M     technician     85711
    1        2   53    F          other     94043
    2        3   23    M         writer     32067
    3        4   24    M     technician     43537
    4        5   33    F          other     15213
    5        6   42    M      executive     98101
    6        7   57    M  administrator     91344
    7        8   36    M  administrator     05201
    8        9   29    M        student     01002
    9       10   53    M         lawyer     90703
  5. 如果您不需要看到所有字段,则可以进行如下操作:
    • 从中筛选出一部分字段。
      users[['user_id', 'age']].head(5)
         user_id  age
      0        1   24
      1        2   53
      2        3   23
      3        4   24
      4        5   33
    • 只做排除个别字段操作。
      users.exclude('zip_code', 'age').head(5)
         user_id  sex  occupation
      0        1    M  technician
      1        2    F       other
      2        3    M      writer
      3        4    M  technician
      4        5    F       other
    • 排除掉一些字段,通过计算得到一些新的列。例如将sexM的置为True,否则为False,并取名为sex_bool
      users.select(users.exclude('zip_code', 'sex'), sex_bool=users.sex == 'M').head(5)
         user_id  age  occupation  sex_bool
      0        1   24  technician      True
      1        2   53       other     False
      2        3   23      writer      True
      3        4   24  technician      True
      4        5   33       other     False
  6. 查看男用户和女用户的个数。
    users.groupby(users.sex).agg(count=users.count())
       sex  count
    0    F    273
    1    M    670
  7. 将用户按职业划分,从高到底进行排序,查看人数最多的前10职业。
    df = users.groupby('occupation').agg(count=users['occupation'].count())
    df.sort(df['count'], ascending=False)[:10]
          occupation  count
    0        student    196
    1          other    105
    2       educator     95
    3  administrator     79
    4       engineer     67
    5     programmer     66
    6      librarian     51
    7         writer     45
    8      executive     32
    9      scientist     31
    或者通过value_counts方法快速实现。该方法返回的行数受到options.df.odps.sort.limit的限制,详情请参见配置选项
    users.occupation.value_counts()[:10]
          occupation  count
    0        student    196
    1          other    105
    2       educator     95
    3  administrator     79
    4       engineer     67
    5     programmer     66
    6      librarian     51
    7         writer     45
    8      executive     32
    9      scientist     31
  8. 通过更直观的图查看这份数据。
    %matplotlib inline
  9. 通过横向的柱状图实现可视化。
    users['occupation'].value_counts().plot(kind='barh', x='occupation', ylabel='prefession')
    <matplotlib.axes._subplots.AxesSubplot at 0x10653cfd0>


  10. 将年龄分为30组,查看年龄分布的直方图。
    users.age.hist(bins=30, title="Distribution of users' ages", xlabel='age', ylabel='count of users')
    <matplotlib.axes._subplots.AxesSubplot at 0x10667a510>


  11. 此时,只需要使用join将这三张表联合起来,然后保存为一张新的表。
    movies = DataFrame(o.get_table('pyodps_ml_100k_movies'))
    ratings = DataFrame(o.get_table('pyodps_ml_100k_ratings'))
    
    o.delete_table('pyodps_ml_100k_lens', if_exists=True)
    lens = movies.join(ratings).join(users).persist('pyodps_ml_100k_lens')
    
    lens.dtypes
    odps.Schema {
      movie_id                            int64
      title                               string
      release_date                        string
      video_release_date                  string
      imdb_url                            string
      user_id                             int64
      rating                              int64
      unix_timestamp                      int64
      age                                 int64
      sex                                 string
      occupation                          string
      zip_code                            string
    }
  12. 将年龄(0到80岁)分成8个年龄段。
    labels = ['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-69', '70-79']
     cut_lens = lens[lens, lens.age.cut(range(0, 81, 10), right=False, labels=labels).rename('年龄分组')]
  13. 取分组和年龄唯一的前10条查看。
    cut_lens['年龄分组', 'age'].distinct()[:10]
       年龄分组  age
    0       0-9    7
    1     10-19   10
    2     10-19   11
    3     10-19   13
    4     10-19   14
    5     10-19   15
    6     10-19   16
    7     10-19   17
    8     10-19   18
    9     10-19   19
  14. 最后,查看在各个年龄分组下,用户的评分总数和评分均值。
    cut_lens.groupby('年龄分组').agg(cut_lens.rating.count().rename('评分总数'), cut_lens.rating.mean().rename('评分均值'))
         年龄分组  评分均值  评分总数
    0       0-9  3.767442        43
    1     10-19  3.486126      8181
    2     20-29  3.467333     39535
    3     30-39  3.554444     25696
    4     40-49  3.591772     15021
    5     50-59  3.635800      8704
    6     60-69  3.648875      2623
    7     70-79  3.649746       197

Dataframe数据处理

本文使用,请您首先下载鸢尾花数据集保存到本地。本文使用DataWorks PyODPS节点功能,详情请参见PyODPS节点

  1. 创建测试数据表
    使用DataWorks表管理功能新建表,完成后单击DDL模式

    输入建表语句如下,完成后提交表。
    CREATE TABLE `pyodps_iris` (
        `sepallength` double COMMENT '片长度(cm)',
        `sepalwidth` double COMMENT '片宽度(cm)',
        `petallength` double COMMENT '瓣长度(cm)',
        `petalwidth` double COMMENT '瓣宽度(cm)',
        `name` string COMMENT '种类'
    ) ;
  2. 上传测试数据
    单击导入

    输入表名称后,上传您刚下载的数据集。

    单击按位置匹配后导入数据。

  3. 新建一个PyODPS节点,用于存放和运行代码。

  4. 输入代码后,单击运行,运行后可在下方运行日志处查看结果。

    代码详情如下。
    from odps.df import DataFrame
    from odps.df import output
    iris = DataFrame(o.get_table('pyodps_iris')) #从ODPS表创建DataFrame对象iris。
    print iris.head(10)
    print iris.sepallength.head(5) #打印iris部分内容。
    
    #使用自定义函数求iris的两列之和。
    print iris.apply(lambda row: row.sepallength + row.sepalwidth, axis=1, reduce=True, types='float').rename('sepaladd').head(3)
    
    #指定函数的输出名称和类型。
    @output(['iris_add', 'iris_sub'], ['float', 'float'])
    def handle(row):
    #使用yield关键字可返回多行结果。
        yield row.sepallength - row.sepalwidth,row.sepallength + row.sepalwidth
        yield row.petallength - row.petalwidth,row.petallength + row.petalwidth
    #打印前5行结果,axis=1表示列的轴沿着水平的方向。
    print iris.apply(handle,axis=1).head(5)