全部產品
Search
文件中心

:資料合併

更新時間:Feb 28, 2024

本文向您介紹DataFrame支援的資料表的JOIN操作、UNION操作等資料合併操作。

前提條件

您需要提前置入以下樣本表資料,用於操作本文中的樣本,其中樣本來源資料下載請參見資料準備,使用到的兩個樣本表結構如下。

>>> from odps.df import DataFrame
>>> movies = DataFrame(o.get_table('pyodps_ml_100k_movies'))
>>> ratings = DataFrame(o.get_table('pyodps_ml_100k_ratings'))

>>> movies.dtypes
odps.Schema {
  movie_id                            int64
  title                               string
  release_date                        string
  video_release_date                  string
  _url                            string
}

>>> ratings.dtypes
odps.Schema {
  user_id                     int64
  movie_id                    int64
  rating                      int64
  unix_timestamp              int64
}

JOIN操作

DataFrame支援對兩個Collection執行join的操作。

  • 如果不指定join的條件,則DataFrame API會尋找名字相同的列,並作為join的條件。

    >>> movies.join(ratings).head(3)
       movie_id              title  release_date  video_release_date                                           url  user_id  rating  unix_timestamp
    0         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...       49       3       888068877
    1         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      621       5       881444887
    2         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      291       3       874833936
  • 顯式指定join的條件。在join時,如果on條件在兩表中所選取的欄位名稱相同,則只會保留其中一個表的此欄位。

    >>> movies.join(ratings, on='movie_id').head(3)
       movie_id              title  release_date  video_release_date                                            url  user_id  rating  unix_timestamp
    0         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...       49       3       888068877
    1         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      621       5       881444887
    2         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      291       3       874833936
  • 在執行其他類型的join操作時,例如left_join,兩表中相同名稱的欄位會被重新命名。

    >>> movies.left_join(ratings, on='movie_id').head(3)
       movie_id_x              title  release_date  video_release_date                                           url  user_id  movie_id_y  rating  unix_timestamp
    0           3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...       49           3       3       888068877
    1           3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      621           3       5       881444887
    2           3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      291           3       3       874833936

    樣本中,movie_id被重新命名為movie_id_xmovie_id_y,這與suffixes參數有關,該參數的預設值為('_x', '_y')。當遇到重名的列時,重名的列會被重新命名為指定的尾碼名。

    >>> ratings2 = ratings[ratings.exclude('movie_id'), ratings.movie_id.rename('movie_id2')]
    >>> ratings2.dtypes
    odps.Schema {
      user_id                     int64
      rating                      int64
      unix_timestamp              int64
      movie_id2                   int64
    }
    >>> movies.join(ratings2, on=[('movie_id', 'movie_id2')]).head(3)
       movie_id              title  release_date  video_release_date                                           url  user_id  rating  unix_timestamp  movie_id2
    0         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...       49       3       888068877          3
    1         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      621       5       881444887          3
    2         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      291       3       874833936          3
  • 也可以在on中直接寫等於運算式。

    >>> movies.join(ratings2, on=[movies.movie_id == ratings2.movie_id2]).head(3)
       movie_id              title  release_date  video_release_date                                           url  user_id  rating  unix_timestamp  movie_id2
    0         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...       49       3       888068877          3
    1         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      621       5       881444887          3
    2         3  Four Rooms (1995)   01-Jan-1995                      http://example.aliyundoc.com/M/title-exact?Four%20Rooms%...      291       3       874833936          3
  • self-join時,可以調用view方法分別提取欄位。

    >>> movies2 = movies.view()
    >>> movies.join(movies2, movies.movie_id == movies2.movie_id)[movies, movies2.movie_id.rename('movie_id2')].head(3)
       movie_id            title_x release_date_x video_release_date_x  \
    0         2   GoldenEye (1995)    01-Jan-1995                 True
    1         3  Four Rooms (1995)    01-Jan-1995                 True
    2         4  Get Shorty (1995)    01-Jan-1995                 True
    
                                              url_x  movie_id2
    0  http://example.aliyundoc.com/M/title-exact?GoldenEye%20(...          2
    1  http://example.aliyundoc.comtitle-exact?Four%20Rooms%...          3
    2  http://example.aliyundoc.com/M/title-exact?Get%20Shorty%...          4

    除了支援join,DataFrame還支援left_joinright_joinouter_join。在執行上述外串連操作時, 預設會為重名列加上_x _y尾碼,可通過在suffixes參數中傳入一個二元tuple進行自訂尾碼。

  • 如果需要在外串連中避免對位次相等的列取重複列,可以指定merge_columns選項。該選項會自動選擇兩列中的非空值作為新列的值。

    >>> movies.left_join(ratings, on='movie_id', merge_columns=True)

使用mapjoin時,只需將mapjoin設為True,執行時會對右表做mapjoin操作。您也可以對分別來自ODPS和Pandas的Collection進行join,或者對分別來自ODPS和資料庫的Collection進行join,該計算會在ODPS上執行。

UNION操作

如果兩張表的欄位和類型都一致(欄位的順序可以不同),則可以使用union或者concat將它們合并成一張表。

>>> mov1 = movies[movies.movie_id < 3]['movie_id', 'title']
>>> mov2 = movies[(movies.movie_id > 3) & (movies.movie_id < 6)]['title', 'movie_id']
>>> mov1.union(mov2)
   movie_id              title
0         1   Toy Story (1995)
1         2   GoldenEye (1995)
2         4  Get Shorty (1995)
3         5     Copycat (1995)

您也可以對分別來自ODPS和Pandas的Collection進行union操作,或者對分別來自ODPS和資料庫的Collection進行union操作,相關的計算會在ODPS上執行。