全部產品
Search
文件中心

MaxCompute:快速入門

更新時間:Mar 20, 2025

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

資料準備

本文將以u.useru.itemu.data資料進行舉例。其中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())
    df1 = df.sort(df['count'], ascending=False)
    print(df1.head(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的限制,詳情請參見配置選項

    df = users.occupation.value_counts()[:10]
    print(df.head(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. 使用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      
      ideo_release_date                 string      
      imdb_url                          string      
      unknown                           int64       
      action                            int64       
      adventure                         int64       
      animation                         int64       
      children                          int64       
      comedy                            int64       
      crime                             int64       
      documentary                       int64       
      drama                             int64       
      fantasy                           int64       
      filmnoir                          int64       
      horror                            int64       
      musical                           int64       
      mystery                           int64       
      romance                           int64       
      scifi                             int64       
      thriller                          int64       
      war                               int64       
      western                           int64       
      user_id                           int64       
      rating                            int64       
      timestamp                         int64       
      age                               int64       
      sex                               string      
      occupation                        string      
      zip_code                          string      
    }

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. 在建立表上單擊右鍵,選擇匯入資料,單擊下一步,上傳您剛下載的資料集。

      image

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

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

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

    from odps import ODPS
    from odps.df import DataFrame, output
    import os
    
    # 確保 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',
    )
    # 從ODPS表建立DataFrame對象iris。
    iris = DataFrame(o.get_table('pyodps_iris'))
    print(iris.head(10))
    # 列印iris部分內容。
    print(iris.sepallength.head(5))
    
    # 使用自訂函數求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