天天看點

Mars 開源月報(2020.3)

本月,Mars 釋出了 0.4.0b1 0.4.0b2 0.3.2 以及 0.3.3 ,點選連結檢視詳細的 Release Notes。本月兩次釋出版本是特殊情況,0.4.0b2 修複了 0.4.0b1 中比較緊急的問題。

Mars 項目釋出周期

這裡先簡述下 Mars 的版本釋出周期。Mars 以一個月為釋出周期,采用雙版本釋出政策,一般會同時釋出 Pre-release 版本和正式版。Pre-release 版本裡會包含更多激進的功能或改動,可能會不穩定,而開發中我們認為穩定的功能或增強會被同步到正式版裡。

檢視

Github 項目的 milestones

可以看到最新的 Pre-release 和正式版本。

Github Projects 頁面

可以看到歸類的 issues 和 PRs。

Mars 開源月報(2020.3)

v0.4 Release 是我們按版本歸檔的進行中的 issues 和 PRs。其他則是按子產品劃分。

新版本功能 Highlight

新版本我們花了大量時間來完善 DataFrame API,經過這個版本的努力,pandas 中的一些常見的接口都得到了支援。

更完善的聚合和分組聚合

  • #1030

    Groupby.aggregate

    支援傳入多個聚合函數。
  • #1054 支援了

    DataFrame.aggregate

    Series.aggregate

  • #1019 #1069

    cummax

    等累積計算。

舉個例子,在 pandas 中我們可以對

movielens 的資料

執行如下操作:

In [1]: import pandas as pd                                                     

In [2]: %%time 
   ...: df = pd.read_csv('Downloads/ml-20m/ratings.csv') 
   ...: df.groupby('movieId').agg({'rating': ['max', 'min', 'mean', 'std']}) 
   ...:  
   ...:                                                                         
CPU times: user 5.41 s, sys: 1.28 s, total: 6.7 s
Wall time: 4.3 s
Out[2]: 
        rating                         
           max  min      mean       std
movieId                                
1          5.0  0.5  3.921240  0.889012
2          5.0  0.5  3.211977  0.951150
3          5.0  0.5  3.151040  1.006642
4          5.0  0.5  2.861393  1.095702
5          5.0  0.5  3.064592  0.982140
...        ...  ...       ...       ...
131254     4.0  4.0  4.000000       NaN
131256     4.0  4.0  4.000000       NaN
131258     2.5  2.5  2.500000       NaN
131260     3.0  3.0  3.000000       NaN
131262     4.0  4.0  4.000000       NaN

[26744 rows x 4 columns]           

我們根據電影的 ID 進行聚合,求使用者評價的最大、最小、平均值以及标準差。

使用 Mars 則可以:

In [1]: import mars.dataframe as md                                             

In [2]: %%time 
   ...: df = md.read_csv('Downloads/ml-20m/ratings.csv') 
   ...: df.groupby('movieId').agg({'rating': ['max', 'min', 'mean', 'std']}).execute() 
   ...:  
   ...:                                                                         
CPU times: user 5.81 s, sys: 6.9 s, total: 12.7 s
Wall time: 1.54 s
Out[2]: 
        rating                         
           max  min      mean       std
movieId                                
1          5.0  0.5  3.921240  0.889012
2          5.0  0.5  3.211977  0.951150
3          5.0  0.5  3.151040  1.006642
4          5.0  0.5  2.861393  1.095702
5          5.0  0.5  3.064592  0.982140
...        ...  ...       ...       ...
131254     4.0  4.0  4.000000       NaN
131256     4.0  4.0  4.000000       NaN
131258     2.5  2.5  2.500000       NaN
131260     3.0  3.0  3.000000       NaN
131262     4.0  4.0  4.000000       NaN

[26744 rows x 4 columns]           

代碼幾乎一緻,除了 Mars 需要通過

execute()

觸發執行。

ratings.csv

有 500M+,使用 Mars 在我的筆記本上運作就可以有數倍加速。當資料量更大的時候,使用 Mars 還可以有更好的加速效果,如果單機無法勝任,也可以使用 Mars 分布式用一緻的代碼加速執行。

排序

還是以

movielens 資料

為例。

In [1]: import pandas as pd                                                                                               

In [2]: %%time 
   ...: ratings = pd.read_csv('Downloads/ml-20m/ratings.csv') 
   ...: movies = pd.read_csv('Downloads/ml-20m/movies.csv') 
   ...: movie_rating = ratings.groupby('movieId', as_index=False).agg({'rating': 'mean'}) 
   ...: result = movie_rating.merge(movies[['movieId', 'title']], on='movieId') 
   ...: result.sort_values(by='rating', ascending=False) 
   ...:  
   ...:                                                                                                                   
CPU times: user 5.17 s, sys: 1.13 s, total: 6.3 s
Wall time: 4.05 s
Out[2]: 
       movieId  rating                                  title
19152    95517     5.0      Barchester Chronicles, The (1982)
21842   105846     5.0                   Only Daughter (2013)
17703    89133     5.0                   Boys (Drenge) (1977)
21656   105187     5.0              Linotype: The Film (2012)
21658   105191     5.0                    Rocaterrania (2009)
...        ...     ...                                    ...
26465   129784     0.5            Xuxa in Crystal Moon (1990)
18534    92479     0.5         Kisses for My President (1964)
26475   129834     0.5  Tom and Jerry: The Lost Dragon (2014)
24207   115631     0.5             Alone for Christmas (2013)
25043   119909     0.5                  Sharpe's Eagle (1993)

[26744 rows x 3 columns]           

主要目标是将資料集中的電影按平均分從高到低進行排列。

到 Mars 這邊,代碼還是幾乎一緻。

In [1]: import mars.dataframe as md                                                                                       

In [2]: %%time 
   ...: ratings = md.read_csv('Downloads/ml-20m/ratings.csv') 
   ...: movies = md.read_csv('Downloads/ml-20m/movies.csv') 
   ...: movie_rating = ratings.groupby('movieId', as_index=False).agg({'rating': 'mean'}) 
   ...: result = movie_rating.merge(movies[['movieId', 'title']], on='movieId') 
   ...: result.sort_values(by='rating', ascending=False).execute() 
   ...:  
   ...:                                                                                                                   
CPU times: user 4.97 s, sys: 6.01 s, total: 11 s
Wall time: 1.39 s
Out[2]: 
       movieId  rating                                  title
19152    95517     5.0      Barchester Chronicles, The (1982)
21842   105846     5.0                   Only Daughter (2013)
17703    89133     5.0                   Boys (Drenge) (1977)
21656   105187     5.0              Linotype: The Film (2012)
21658   105191     5.0                    Rocaterrania (2009)
...        ...     ...                                    ...
26465   129784     0.5            Xuxa in Crystal Moon (1990)
18534    92479     0.5         Kisses for My President (1964)
26475   129834     0.5  Tom and Jerry: The Lost Dragon (2014)
24207   115631     0.5             Alone for Christmas (2013)
25043   119909     0.5                  Sharpe's Eagle (1993)

[26744 rows x 3 columns]           

Mars 的排序采用了并行正則采樣排序算法,在我們的文章(

連結

)中已經做了介紹,這裡不再贅述。

更完善的索引支援

Mars 在之前的版本中就支援了

iloc

,現在我們也支援了其他的索引方法。

通過

loc

的支援,使得基于索引的資料的查找更加友善。

In [1]: import mars.dataframe as md 
  
In [3]: import mars.tensor as mt

In [8]: df = md.DataFrame(mt.random.rand(10000, 10), index=md.date_range('2000-1-1', periods=10000))                      

In [9]: df.loc['2020-3-25'].execute()                                                                                     
Out[9]: 
0    0.372354
1    0.139235
2    0.511007
3    0.102200
4    0.908454
5    0.144455
6    0.290627
7    0.248334
8    0.912666
9    0.830526
Name: 2020-03-25 00:00:00, dtype: float64           

自定義函數、字元串和時間處理

  • #1038 增加了 apply 的支援。
  • #1063

    md.Series.str

    md.Series.dt

    來處理字元串和時間列。

我們可以利用 apply 來計算每個城市(

資料集

)到杭州(東經120°12′,北緯30°16′)的距離。

In [1]: import numpy as np                                                                                                

In [2]: def haversine(lat1, lon1, lat2, lon2): 
   ...:     dlon = np.radians(lon2 - lon1) 
   ...:     dlat = np.radians(lat2 - lat1) 
   ...:     a = np.sin(dlat / 2) ** 2 + np.cos(np.radians(lat1)) * np.cos(np.radians(lat2)) * np.sin(dlon / 2) ** 2 
   ...:     c = 2 * np.arcsin(np.sqrt(a)) 
   ...:     r =  6371 
   ...:     return c * r 
   ...:                                                                                                                   

In [4]: import mars.dataframe as md                                                                                       

In [5]: df = md.read_csv('Downloads/world-cities-database/worldcitiespop.csv', chunk_bytes='16M', dtype={'Region': object}
   ...: )                                                                                                                 

In [6]: df.execute(fetch=False)                                                                                           

In [8]: df.apply(lambda r: haversine(r['Latitude'], r['Longitude'], 30.25, 120.17), result_type='reduce', axis=1).execute()                                                                                                                 
Out[8]: 
0          9789.135208
1          9788.270528
2          9788.270528
3          9788.270528
4          9789.307210
              ...     
248061    10899.720735
248062    11220.703197
248063    10912.645753
248064    11318.038981
248065    11141.080171
Length: 3173958, dtype: float64           

移動視窗函數

  • #1045 增加了 rolling 移動視窗的支援。

移動視窗函數在金融領域使用頻率很高,rolling 是在一個固定長度(也可能是固定的時間間隔)上進行一些聚合計算。以下是一個例子。

In [1]: import pandas_datareader.data as web                                                                                                                      

In [2]: data = web.DataReader("^TWII", "yahoo", "2000-01-01","2020-03-25")                                                                                        

In [3]: import mars.dataframe as md                                                                                                                               

In [4]: df = md.DataFrame(data)                                                                                                                                   

In [5]: df.rolling(10, min_periods=1).mean().execute()                                                                                                            
Out[5]: 
                    High           Low          Open         Close     Volume     Adj Close
Date                                                                                       
2000-01-04   8803.610352   8642.500000   8644.910156   8756.549805        0.0   8756.517578
2000-01-05   8835.645020   8655.259766   8667.754883   8803.209961        0.0   8803.177734
2000-01-06   8898.426758   8714.809896   8745.356445   8842.816732        0.0   8842.784180
2000-01-07   8909.012451   8720.964844   8772.374756   8844.580078        0.0   8844.547607
2000-01-10   8952.413867   8755.129883   8806.285742   8896.183984        0.0   8896.151172
...                  ...           ...           ...           ...        ...           ...
2020-03-19  10423.317090  10083.132910  10370.730078  10180.533887  4149640.0  10180.533887
2020-03-20  10202.623047   9833.786914  10105.280078   9971.761914  4366130.0   9971.761914
2020-03-23   9983.399023   9611.036914   9885.659082   9763.000977  3990040.0   9763.000977
2020-03-24   9821.716016   9436.392969   9703.275098   9591.208984  3927690.0   9591.208984
2020-03-25   9685.129980   9290.444922   9543.636035   9466.308984  4003760.0   9466.308984

[4974 rows x 6 columns]           

下一個版本計劃

下一個版本會是 0.4.0rc1 和 0.3.4,我們仍然會專注提升 DataFrame API 的覆寫率和性能,提升穩定性,并增加文檔。

如果對 Mars 感興趣,可以關注

Mars 團隊專欄

,或者釘釘掃二維碼加入 Mars 讨論群。

Mars 開源月報(2020.3)