本文向您介绍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_x、movie_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_join、right_join和outer_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上执行。