全部產品
Search
文件中心

:快速入門

更新時間:Feb 28, 2024

本文為您介紹如何建立和操作DataFrame對象,以及使用DataFrame完成基本的資料處理。

資料準備

本文將以movielens 100K進行舉例,下載ml-100k.zip到本地。其中u.user是使用者相關的資料,u.item是電影相關的資料,u.data是評分有關的資料。

  1. 建立表:

    • pyodps_ml_100k_users(使用者相關的資料)。

      create table if not exists pyodps_ml_100k_users
      (
        user_id    BIGINT COMMENT '使用者id',
        age        BIGINT COMMENT '年齡',
        sex        STRING COMMENT '性別',
        occupation STRING COMMENT '職業',
        zip_code   STRING COMMENT '郵編'
      );
    • pyodps_ml_100k_movies(電影相關的資料)。

      CREATE TABLE IF NOT EXISTS pyodps_ml_100k_movies
      (
          movie_id            BIGINT COMMENT '電影 ID'
          ,title              STRING COMMENT '電影標題'
          ,release_date       STRING COMMENT '上映日期'
          ,video_release_date STRING COMMENT '視頻發布日期'
          ,IMDb_URL           STRING COMMENT 'IMDb 連結'
          ,unknown            TINYINT COMMENT '未知'
          ,Action             TINYINT COMMENT '動作'
          ,Adventure          TINYINT COMMENT '冒險'
          ,Animation          TINYINT COMMENT '動畫'
          ,Children           TINYINT COMMENT '兒童'
          ,Comedy             TINYINT COMMENT '喜劇'
          ,Crime              TINYINT COMMENT '犯罪'
          ,Documentary        TINYINT COMMENT '紀錄片'
          ,Drama              TINYINT COMMENT '戲劇'
          ,Fantasy            TINYINT COMMENT '奇幻'
          ,FilmNoir           TINYINT COMMENT '黑色電影'
          ,Horror             TINYINT COMMENT '恐怖'
          ,Musical            TINYINT COMMENT '音樂'
          ,Mystery            TINYINT COMMENT '懸疑'
          ,Romance            TINYINT COMMENT '浪漫'
          ,SciFi              TINYINT COMMENT '科幻'
          ,Thriller           TINYINT COMMENT '驚悚'
          ,War                TINYINT COMMENT '戰爭'
          ,Western            TINYINT COMMENT '西部'
      );
    • pyodps_ml_100k_ratings(評分有關的資料)。

      CREATE TABLE IF NOT EXISTS pyodps_ml_100k_ratings
      (
          user_id    BIGINT COMMENT '使用者id'
          ,movie_id  BIGINT COMMENT '電影id'
          ,rating    BIGINT COMMENT '得分'
          ,timestamp BIGINT COMMENT '時間戳記'
      )
  2. 基於Tunnel Upload 將本機資料檔案內容匯入MaxCompute的表中。更多Tunnel操作,請參見Tunnel命令

    Tunnel upload -fd | path_to_file/u.user pyodps_ml_100k_users;
    Tunnel upload -fd | path_to_file/u.item pyodps_ml_100k_movies;
    Tunnel upload -fd | path_to_file/u.data pyodps_ml_100k_ratings;

DataFrame對象操作

現在已經有了三張表,分別是pyodps_ml_100k_movies(電影相關的資料)、pyodps_ml_100k_users(使用者相關的資料)、pyodps_ml_100k_ratings(評分有關的資料)。以下樣本使用IPython運行。

說明

確保已經安裝了Python。IPython是基於Python的,所以需要先安裝Python環境。接著通過pip install IPython 安裝IPython。安裝完成後,可以通過執行IPython命令來啟動IPython的互動式環境,開始編寫和執行Python代碼。

  1. 建立ODPS對象。

    import os
    from odps import ODPS
    # 確保 ALIBABA_CLOUD_ACCESS_KEY_ID 環境變數設定為使用者 Access Key ID,
    # ALIBABA_CLOUD_ACCESS_KEY_SECRET 環境變數設定為使用者 Access Key Secret,
    # 不建議直接使用 Access Key ID / Access Key Secret 字串
    o = ODPS(
        os.getenv('ALIBABA_CLOUD_ACCESS_KEY_ID'),
        os.getenv('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),
        project='your-default-project',
        endpoint='your-end-point',
    )
    
  2. 通過傳入Table對象建立一個DataFrame對象。

    from odps.df import DataFrame
    users = DataFrame(o.get_table('pyodps_ml_100k_users'))
  3. 您可以通過dtypes屬性查看這個DataFrame的欄位及欄位類型。

    print(users.dtypes)

    傳回值

    odps.Schema {
      user_id             int64
      age                 int64
      sex                 string
      occupation          string
      zip_code            string
    }
  4. 通過head方法,您可以取前N條資料並進行快速預覽。

    print(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. 如果您不需要看到所有欄位,則可以進行如下操作:

    • 從中篩選出一部分欄位。

      print(users[['user_id', 'age']].head(5))

      傳回值

         user_id  age
      0        1   24
      1        2   53
      2        3   23
      3        4   24
      4        5   33
    • 只做排除個別欄位操作。

      print(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

      print(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. 查看男使用者和女使用者的個數。

    print(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())
    print(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的限制,詳情請參見配置選項

    print(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. 通過更直觀的圖查看這份資料。在 IPython 中可以啟用內嵌圖表 。

    %matplotlib inline
  9. 將年齡分為30組,查看年齡分布的長條圖。

    users.age.hist(bins=30, title="Distribution of users' ages", xlabel='age', ylabel='count of users')

    顯示的圖表為

    可視化圖

  10. 此時,只需要使用join將這三張表聯合起來,然後儲存為一張新的表pyodps_ml_100k_lens

    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')
    
    print(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
    }
  11. 將年齡(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('年齡分組')]
  12. 取分組和年齡唯一的前10條查看。

    print(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
  13. 最後,查看在各個年齡分組下,使用者的評分總數和評分均值。

    print(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 3任務

  1. 建立測試資料表 。

    使用DataWorks表管理功能建立表:

    1. 開啟相應的商務程序,按右鍵MaxCompute,選擇建立表。在建立表對話方塊中,選擇路徑,輸入名稱,單擊建立,進入表的編輯頁面。

    2. 選擇編輯頁面左上方DDLimage.png

    3. 輸入建表語句如下,完成後提交表。

      CREATE TABLE pyodps_iris (
          sepallength double COMMENT '片長度(cm)',
          sepalwidth double COMMENT '片寬度(cm)',
          petallength double COMMENT '瓣長度(cm)',
          petalwidth double COMMENT '瓣寬度(cm)',
          name string COMMENT '種類'
      ) ;
  2. 上傳測試資料 。

    1. 在建立表上單擊右鍵,選擇匯入資料,單擊下一步,上傳您剛下載的資料集。

      匯入資料

    2. 單擊按位置匹配後匯入資料。

  3. 開啟相應的商務程序,按右鍵MaxCompute,選擇建立節點,選擇PyODPS 3,建立一個PyODPS節點,用於存放和運行代碼。

  4. 輸入代碼後,單擊運行image.png,運行後可在下方作業記錄處查看結果。代碼詳情如下。

    from odps.df import DataFrame, 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))

    運行結果:

    # print(iris.head(10))
       sepallength  sepalwidth  petallength  petalwidth         name
    0          4.9         3.0          1.4         0.2  Iris-setosa
    1          4.7         3.2          1.3         0.2  Iris-setosa
    2          4.6         3.1          1.5         0.2  Iris-setosa
    3          5.0         3.6          1.4         0.2  Iris-setosa
    4          5.4         3.9          1.7         0.4  Iris-setosa
    5          4.6         3.4          1.4         0.3  Iris-setosa
    6          5.0         3.4          1.5         0.2  Iris-setosa
    7          4.4         2.9          1.4         0.2  Iris-setosa
    8          4.9         3.1          1.5         0.1  Iris-setosa
    9          5.4         3.7          1.5         0.2  Iris-setosa
    
    
    # print(iris.sepallength.head(5))
       sepallength
    0          4.9
    1          4.7
    2          4.6
    3          5.0
    4          5.4
    
    # print(iris.apply(lambda row: row.sepallength + row.sepalwidth, axis=1, reduce=True, types='float').rename('sepaladd').head(3))
       sepaladd
    0       7.9
    1       7.9
    2       7.7
    
    # print(iris.apply(handle,axis=1).head(5))
       iris_add  iris_sub
    0       1.9       7.9
    1       1.2       1.6
    2       1.5       7.9
    3       1.1       1.5
    4       1.5       7.7