本文為您介紹如何建立和操作DataFrame對象,以及使用DataFrame完成基本的資料處理。
資料準備
本文將以movielens 100K進行舉例,下載ml-100k.zip到本地。其中u.user是使用者相關的資料,u.item是電影相關的資料,u.data是評分有關的資料。
建立表:
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 '時間戳記' )
基於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代碼。
建立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', )
通過傳入Table對象建立一個DataFrame對象。
from odps.df import DataFrame users = DataFrame(o.get_table('pyodps_ml_100k_users'))
您可以通過
dtypes
屬性查看這個DataFrame的欄位及欄位類型。print(users.dtypes)
傳回值
odps.Schema { user_id int64 age int64 sex string occupation string zip_code string }
通過
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
如果您不需要看到所有欄位,則可以進行如下操作:
從中篩選出一部分欄位。
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
排除掉一些欄位,通過計算得到一些新的列。例如將
sex
為M
的置為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
查看男使用者和女使用者的個數。
print(users.groupby(users.sex).agg(count=users.count()))
傳回值
sex count 0 F 273 1 M 670
將使用者按職業劃分,從高到低進行排序,查看人數最多的前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
通過更直觀的圖查看這份資料。在 IPython 中可以啟用內嵌圖表 。
%matplotlib inline
將年齡分為30組,查看年齡分布的長條圖。
users.age.hist(bins=30, title="Distribution of users' ages", xlabel='age', ylabel='count of users')
顯示的圖表為
此時,只需要使用
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 }
將年齡(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('年齡分組')]
取分組和年齡唯一的前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
最後,查看在各個年齡分組下,使用者的評分總數和評分均值。
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任務。
建立測試資料表 。
使用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 '種類' ) ;
上傳測試資料 。
在建立表上單擊右鍵,選擇匯入資料,單擊下一步,上傳您剛下載的資料集。
單擊按位置匹配後匯入資料。
開啟相應的商務程序,按右鍵MaxCompute,選擇建立節點,選擇PyODPS 3,建立一個PyODPS節點,用於存放和運行代碼。
輸入代碼後,單擊運行,運行後可在下方作業記錄處查看結果。代碼詳情如下。
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