本月,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。

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
自定義函數、字元串和時間處理
我們可以利用 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 讨論群。