您可以对DataFrame对象执行排序、去重、采样、数据变换操作。
前提条件
您需要提前完成以下步骤,用于操作本文中的示例:
准备示例表pyodps_iris,详情请参见Dataframe数据处理。
创建DataFrame。
from odps.df import DataFrame iris = DataFrame(o.get_table('pyodps_iris'))
排序
排序操作只能作用于Collection。
调用
sort
或者sort_values
方法进行排序。>>> iris.sort('sepalwidth').head(5) sepallength sepalwidth petallength petalwidth name 0 5.0 2.0 3.5 1.0 Iris-versicolor 1 6.2 2.2 4.5 1.5 Iris-versicolor 2 6.0 2.2 5.0 1.5 Iris-virginica 3 6.0 2.2 4.0 1.0 Iris-versicolor 4 5.5 2.3 4.0 1.3 Iris-versicolor
设置参数
ascending=False;
进行降序排列。>>> iris.sort('sepalwidth', ascending=False).head(5) sepallength sepalwidth petallength petalwidth name 0 5.7 4.4 1.5 0.4 Iris-setosa 1 5.5 4.2 1.4 0.2 Iris-setosa 2 5.2 4.1 1.5 0.1 Iris-setosa 3 5.8 4.0 1.2 0.2 Iris-setosa 4 5.4 3.9 1.3 0.4 Iris-setosa
设置
-
实现降序排列。>>> iris.sort(-iris.sepalwidth).head(5) sepallength sepalwidth petallength petalwidth name 0 5.7 4.4 1.5 0.4 Iris-setosa 1 5.5 4.2 1.4 0.2 Iris-setosa 2 5.2 4.1 1.5 0.1 Iris-setosa 3 5.8 4.0 1.2 0.2 Iris-setosa 4 5.4 3.9 1.3 0.4 Iris-setosa
实现多字段排序。
>>> iris.sort(['sepalwidth', 'petallength']).head(5) sepallength sepalwidth petallength petalwidth name 0 5.0 2.0 3.5 1.0 Iris-versicolor 1 6.0 2.2 4.0 1.0 Iris-versicolor 2 6.2 2.2 4.5 1.5 Iris-versicolor 3 6.0 2.2 5.0 1.5 Iris-virginica 4 4.5 2.3 1.3 0.3 Iris-setosa
多字段排序时,如果是升序降序不同,
ascending
参数可以用于传入一个列表,长度必须等同于排序的字段,它们的值都是BOOLEAN类型。>>> iris.sort(['sepalwidth', 'petallength'], ascending=[True, False]).head(5) sepallength sepalwidth petallength petalwidth name 0 5.0 2.0 3.5 1.0 Iris-versicolor 1 6.0 2.2 5.0 1.5 Iris-virginica 2 6.2 2.2 4.5 1.5 Iris-versicolor 3 6.0 2.2 4.0 1.0 Iris-versicolor 4 6.3 2.3 4.4 1.3 Iris-versicolor
下面代码可以实现同样的效果。
>>> iris.sort(['sepalwidth', -iris.petallength]).head(5) sepallength sepalwidth petallength petalwidth name 0 5.0 2.0 3.5 1.0 Iris-versicolor 1 6.0 2.2 5.0 1.5 Iris-virginica 2 6.2 2.2 4.5 1.5 Iris-versicolor 3 6.0 2.2 4.0 1.0 Iris-versicolor 4 6.3 2.3 4.4 1.3 Iris-versicolor
说明由于ODPS要求排序必须指定个数,所以在ODPS后端执行时,会通过
options.df.odps.sort.limit
指定排序个数,这个值默认是10000。如果需要排序尽量多的数据,可以把这个值设到较大的值。但是,这样可能会导致OOM。
去重
您可以通过以下三种方式调用
distinct
方法,对Collection进行去重操作。>>> iris[['name']].distinct() name 0 Iris-setosa 1 Iris-versicolor 2 Iris-virginica
>>> iris.distinct('name') name 0 Iris-setosa 1 Iris-versicolor 2 Iris-virginica
>>> iris.distinct('name', 'sepallength').head(3) name sepallength 0 Iris-setosa 4.3 1 Iris-setosa 4.4 2 Iris-setosa 4.5
您可以调用
unique
对Sequence进行去重操作,但是调用unique
的Sequence不能用在列选择中。>>> iris.name.unique() name 0 Iris-setosa 1 Iris-versicolor 2 Iris-virginica
错误示例如下。
>>> iris[iris.name, iris.name.unique()]
采样
要对一个Collection的数据采样,可以调用sample
方法。PyODPS支持以下四种采样方式:
除了按份数采样外,其余方法如果要在ODPS DataFrame上执行,需要Project支持XFlow,否则,这些方法只能在Pandas DataFrame后端上执行。
按份数采样
在这种采样方式下,数据被分为
parts
份,可选择选取的份数序号。>>> iris.sample(parts=10) # 分成10份,默认取第0份。 >>> iris.sample(parts=10, i=0) # 手动指定取第0份。 >>> iris.sample(parts=10, i=[2, 5]) # 分成10份,取第2和第5份。 >>> iris.sample(parts=10, columns=['name', 'sepalwidth']) # 根据name和sepalwidth的值做采样。
按权重列采样
在这种采样方式下,您可以指定权重列和数据条数、采样比例。指定
replace
参数为True可启用放回采样。>>> iris.sample(n=100, weights='sepal_length') >>> iris.sample(n=100, weights='sepal_width', replace=True)
分层采样
在这种采样方式下,您可以指定用于分层的标签列,同时为需要采样的每个标签指定采样比例(
frac
参数)或条数 (n
参数)。暂不支持放回采样。>>> iris.sample(strata='category', n={'Iris Setosa': 10, 'Iris Versicolour': 10}) >>> iris.sample(strata='category', frac={'Iris Setosa': 0.5, 'Iris Versicolour': 0.4})
数据缩放
DataFrame支持通过最大、最小值或平均值、标准差对数据进行缩放。示例数据如下。
name id fid
0 name1 4 5.3
1 name2 2 3.5
2 name2 3 1.5
3 name1 4 4.2
4 name1 3 2.2
5 name1 3 4.1
使用
min_max_scale
方法进行归一化。df.min_max_scale(columns=['fid']) name id fid 0 name1 4 1.000000 1 name2 2 0.526316 2 name2 3 0.000000 3 name1 4 0.710526 4 name1 3 0.184211 5 name1 3 0.684211
min_max_scale
还支持使用feature_range
参数指定输出值的范围。例如,需要使输出值在 (-1, 1) 范围内,示例如下。df.min_max_scale(columns=['fid'], feature_range=(-1, 1)) name id fid 0 name1 4 1.000000 1 name2 2 0.052632 2 name2 3 -1.000000 3 name1 4 0.421053 4 name1 3 -0.631579 5 name1 3 0.368421
如果需要保留原始值,可以使用
preserve
参数。此时,缩放后的数据将会以新增列的形式追加到数据中,列名默认为原列名追加_scaled后缀,该后缀可使用suffix
参数更改。df.min_max_scale(columns=['fid'], preserve=True) name id fid fid_scaled 0 name1 4 5.3 1.000000 1 name2 2 3.5 0.526316 2 name2 3 1.5 0.000000 3 name1 4 4.2 0.710526 4 name1 3 2.2 0.184211 5 name1 3 4.1 0.684211
min_max_scale
也支持使用group
参数指定一个或多个分组列,在分组列中分别取最值进行缩放。df.min_max_scale(columns=['fid'], group=['name']) name id fid 0 name1 4 1.000000 1 name1 4 0.645161 2 name1 3 0.000000 3 name1 3 0.612903 4 name2 2 1.000000 5 name2 3 0.000000
结果显示,
name1
和name2
两组均按组中的最值进行了缩放。使用
std_scale
方法可以依照标准正态分布对数据进行调整。std_scale
同样支持preserve
参数保留原始列以及使用group
进行分组。df.std_scale(columns=['fid']) name id fid 0 name1 4 1.436467 1 name2 2 0.026118 2 name2 3 -1.540938 3 name1 4 0.574587 4 name1 3 -0.992468 5 name1 3 0.496234
空值处理
DataFrame支持筛去空值以及填充空值的功能。示例数据如下。
id name f1 f2 f3 f4
0 0 name1 1.0 NaN 3.0 4.0
1 1 name1 2.0 NaN NaN 1.0
2 2 name1 3.0 4.0 1.0 NaN
3 3 name1 NaN 1.0 2.0 3.0
4 4 name1 1.0 NaN 3.0 4.0
5 5 name1 1.0 2.0 3.0 4.0
6 6 name1 NaN NaN NaN NaN
使用
dropna
,删除subset
中包含空值的行。df.dropna(subset=['f1', 'f2', 'f3', 'f4']) id name f1 f2 f3 f4 0 5 name1 1.0 2.0 3.0 4.0
如果行中包含非空值则不删除,可以使用
how=’all’
。df.dropna(how='all', subset=['f1', 'f2', 'f3', 'f4']) id name f1 f2 f3 f4 0 0 name1 1.0 NaN 3.0 4.0 1 1 name1 2.0 NaN NaN 1.0 2 2 name1 3.0 4.0 1.0 NaN 3 3 name1 NaN 1.0 2.0 3.0 4 4 name1 1.0 NaN 3.0 4.0 5 5 name1 1.0 2.0 3.0 4.0
使用
thresh
参数指定行中至少要有多少个非空值。df.dropna(thresh=3, subset=['f1', 'f2', 'f3', 'f4']) id name f1 f2 f3 f4 0 0 name1 1.0 NaN 3.0 4.0 2 2 name1 3.0 4.0 1.0 NaN 3 3 name1 NaN 1.0 2.0 3.0 4 4 name1 1.0 NaN 3.0 4.0 5 5 name1 1.0 2.0 3.0 4.0
调用
fillna
方法,使用常数或已有的列来填充未知值。使用常数填充未知值。
df.fillna(100, subset=['f1', 'f2', 'f3', 'f4']) id name f1 f2 f3 f4 0 0 name1 1.0 100.0 3.0 4.0 1 1 name1 2.0 100.0 100.0 1.0 2 2 name1 3.0 4.0 1.0 100.0 3 3 name1 100.0 1.0 2.0 3.0 4 4 name1 1.0 100.0 3.0 4.0 5 5 name1 1.0 2.0 3.0 4.0 6 6 name1 100.0 100.0 100.0 100.0
使用一个已有的列填充未知值。
df.fillna(df.f2, subset=['f1', 'f2', 'f3', 'f4']) id name f1 f2 f3 f4 0 0 name1 1.0 NaN 3.0 4.0 1 1 name1 2.0 NaN NaN 1.0 2 2 name1 3.0 4.0 1.0 4.0 3 3 name1 1.0 1.0 2.0 3.0 4 4 name1 1.0 NaN 3.0 4.0 5 5 name1 1.0 2.0 3.0 4.0 6 6 name1 NaN NaN NaN NaN
DataFrame提供了向前、向后填充的功能。您可以按照表格中的取值范围为
method
参数进行赋值。取值
含义
bfill、backfill
向前填充。
ffill、pad
向后填充。
示例
df.fillna(method='bfill', subset=['f1', 'f2', 'f3', 'f4']) id name f1 f2 f3 f4 0 0 name1 1.0 3.0 3.0 4.0 1 1 name1 2.0 1.0 1.0 1.0 2 2 name1 3.0 4.0 1.0 NaN 3 3 name1 1.0 1.0 2.0 3.0 4 4 name1 1.0 3.0 3.0 4.0 5 5 name1 1.0 2.0 3.0 4.0 6 6 name1 NaN NaN NaN NaN df.fillna(method='ffill', subset=['f1', 'f2', 'f3', 'f4']) id name f1 f2 f3 f4 0 0 name1 1.0 1.0 3.0 4.0 1 1 name1 2.0 2.0 2.0 1.0 2 2 name1 3.0 4.0 1.0 1.0 3 3 name1 NaN 1.0 2.0 3.0 4 4 name1 1.0 1.0 3.0 4.0 5 5 name1 1.0 2.0 3.0 4.0 6 6 name1 NaN NaN NaN NaN
您也可以使用
ffill
、bfill
函数简化代码。ffill
等价于fillna(method=’ffill’)
;bfill
等价于fillna(method=’bfill’)
。