与 PyODPS DataFrame 的比较#
PyODPS DataFrame 是 MaxCompute 提供的类似 DataFrame 的包,是 PyODPS 包的一部分。它可以让 Python 数据分析人员使用类似于 pandas 的一组操作符来查询 MaxCompute 数据。尽管操作符相似,但两套 API 的用法差异很大。仅凭 pandas 的知识,开发者可能难以深入使用 PyODPS DataFrame。
虽然 PyODPS DataFrame 仍然是 PyODPS 的一部分,但建议使用 MaxFrame 创建新应用,以享受其与 pandas 的兼容性。
对象抽象#
PyODPS DataFrame 没有索引。这意味着大多数依赖索引的 pandas API 无法使用或不完全支持。
例如,pandas 中的算术运算依赖于索引对齐。也就是说,先对两个 DataFrame 进行对齐,然后执行算术运算。
>>> series1 = pd.Series([2, 1, 3], index=[1, 2, 4])
>>> series2 = pd.Series([1, 5, 6], index=[1, 3, 4])
>>> series1 + series2
1 3.0
2 NaN
3 NaN
4 9.0
dtype: float64
然而,当索引缺失时,这种操作不被支持。
为了支持这种操作,在 MaxFrame 中需要为 DataFrame 或 Series 添加索引列。如果索引缺失,则会添加一个默认的 RangeIndex。因此上述语句可以被支持。
PyODPS DataFrame 和 MaxFrame 之间的另一个巨大差异在于,在 PyODPS DataFrame 中,数据对象和操作符的表示是混合的,这可能会让初学者感到困惑。例如,
df = o.get_table('table_name').to_df() # df is a DataFrame instance
df2 = df["col1", "col2"] # df2 is a CollectionExpr instance
在第二行中,df2 是 CollectionExpr 的一个实例,意味着它是一个表达式,与 DataFrame 实例不同。然而,所有 DataFrame 函数都可以直接应用于 df2,与 DataFrame 实例没有什么不同。
而在 MaxFrame 中,数据对象和操作符是分别定义的。用户交互的数据对象都是少数几个数据类的实例,即 DataFrame、Series 或 Index。对于上面的例子,现在所有实例都是 DataFrame。
df = md.read_odps_table('table_name') # df is a DataFrame instance
df2 = df[["col1", "col2"]] # df2 is also a DataFrame instance
函数#
PyODPS DataFrame 中的函数与 pandas 并不完全兼容。因此,要使用 PyODPS DataFrame 编写代码,用户需要先阅读文档。而 MaxFrame 的目标是创建与 pandas 兼容的 API。因此,PyODPS DataFrame 和 MaxFrame 之间存在 API 差异。这些差异列在下面。以 mf. 开头的方法表示这些非 pandas 方法是在 MaxFrame 中添加的,以便从 PyODPS DataFrame 迁移到 MaxFrame。请注意,在重写代码之前需要阅读这些函数的 API 文档。
PyODPS DataFrame API |
MaxFrame API |
|---|---|
DataFrame.append_id |
不需要。默认情况下会添加 DataFrame 索引 |
DataFrame.bloom_filter |
尚未实现 |
DataFrame.boxplot |
DataFrame.plot.boxplot |
DataFrame.concat |
maxframe.dataframe.concat |
DataFrame.describe |
DataFrame.describe |
DataFrame.distinct |
DataFrame.drop_duplicates |
DataFrame.except_ |
DataFrame.merge 与过滤器 |
DataFrame.exclude |
DataFrame.drop |
DataFrame.extract_kv |
尚未实现 |
DataFrame.hist |
DataFrame.plot.hist |
DataFrame.inner_join |
DataFrame.merge |
DataFrame.intersect |
DataFrame.merge |
DataFrame.left_join |
DataFrame.merge |
DataFrame.limit |
DataFrame.head |
DataFrame.map_reduce |
DataFrame.mf.map_reduce |
DataFrame.minmax_scale |
尚未实现 |
DataFrame.outer_join |
DataFrame.merge |
DataFrame.persist |
DataFrame.to_odps_table |
DataFrame.reshuffle |
DataFrame.mf.reshuffle |
DataFrame.right_join |
DataFrame.merge |
DataFrame.setdiff |
DataFrame.merge |
DataFrame.split |
尚未实现 |
DataFrame.std_scale |
尚未实现 |
DataFrame.sort |
DataFrame.sort_values |
DataFrame.switch |
maxframe.dataframe.case_when |
DataFrame.to_kv |
尚未实现 |
DataFrame.union |
maxframe.dataframe.concat |
DatetimeSequenceExpr.date |
Series.dt.date |
DatetimeSequenceExpr.day |
Series.dt.day |
DatetimeSequenceExpr.dayofweek |
Series.dt.dayofweek |
DatetimeSequenceExpr.dayofyear |
Series.dt.dayofyear |
DatetimeSequenceExpr.hour |
Series.dt.hour |
DatetimeSequenceExpr.is_month_end |
Series.dt.is_month_end |
DatetimeSequenceExpr.is_month_start |
Series.dt.is_month_start |
DatetimeSequenceExpr.is_year_end |
Series.dt.is_year_end |
DatetimeSequenceExpr.is_year_start |
Series.dt.is_year_start |
DatetimeSequenceExpr.microsecond |
Series.dt.microsecond |
DatetimeSequenceExpr.min |
Series.dt.min |
DatetimeSequenceExpr.minute |
Series.dt.minute |
DatetimeSequenceExpr.month |
Series.dt.month |
DatetimeSequenceExpr.second |
Series.dt.second |
DatetimeSequenceExpr.strftime |
Series.dt.strftime |
DatetimeSequenceExpr.unix_timestamp |
尚未实现 |
DatetimeSequenceExpr.week |
Series.dt.week |
DatetimeSequenceExpr.weekday |
Series.dt.weekday |
DatetimeSequenceExpr.weekofyear |
Series.dt.weekofyear |
DatetimeSequenceExpr.year |
Series.dt.year |
SequenceExpr.degrees |
np.degrees(Series) |
SequenceExpr.radians |
np.radians(Series) |
SequenceExpr.tolist |
Series.to_numpy |
SequenceExpr.to_datetime |
maxframe.dataframe.to_datetime |
SequenceExpr.topk |
尚未实现 |
SequenceExpr.trunc |
np.trunc(Series) |
SequenceExpr.hll_count |
尚未实现 |
StringSequenceExpr.capitalize |
Series.str.capitalize |
StringSequenceExpr.contains |
Series.str.contains |
StringSequenceExpr.count |
Series.str.count |
StringSequenceExpr.endswith |
Series.str.endswith |
StringSequenceExpr.find |
Series.str.find |
StringSequenceExpr.len |
Series.str.len |
StringSequenceExpr.ljust |
Series.str.ljust |
StringSequenceExpr.lower |
Series.str.lower |
StringSequenceExpr.lstrip |
Series.str.lstrip |
StringSequenceExpr.pad |
Series.str.pad |
StringSequenceExpr.repeat |
Series.str.repeat |
StringSequenceExpr.replace |
Series.str.replace |
StringSequenceExpr.rfind |
Series.str.rfind |
StringSequenceExpr.rjust |
Series.str.rjust |
StringSequenceExpr.rstrip |
Series.str.rstrip |
StringSequenceExpr.slice |
Series.str.slice |
StringSequenceExpr.startswith |
Series.str.startswith |
StringSequenceExpr.strip |
Series.str.strip |
StringSequenceExpr.swapcase |
Series.str.swapcase |
StringSequenceExpr.title |
Series.str.title |
StringSequenceExpr.translate |
Series.str.translate |
StringSequenceExpr.upper |
Series.str.upper |
StringSequenceExpr.zfill |
Series.str.zfill |
StringSequenceExpr.isalnum |
Series.str.isalnum |
StringSequenceExpr.isalpha |
Series.str.isalpha |
StringSequenceExpr.isdigit |
Series.str.isdigit |
StringSequenceExpr.isspace |
Series.str.isspace |
StringSequenceExpr.islower |
Series.str.islower |
StringSequenceExpr.isupper |
Series.str.isupper |
StringSequenceExpr.istitle |
Series.str.istitle |
StringSequenceExpr.isnumeric |
Series.str.isnumeric |
StringSequenceExpr.isdecimal |
Series.str.isdecimal |
执行#
PyODPS DataFrame 和 MaxFrame 都使用惰性执行来提升代码优化的效率。然而,调用这些作业的方式发生了变化。