DataFrame中所有二维数据集上的操作都属于CollectionExpr,可视为一张MaxCompute表或一张电子表单,DataFrame对象也是CollectionExpr的特例。CollectionExpr中包含针对二维数据集的列操作、筛选、变换等大量操作。

获取类型

dtypes可以用来获取CollectionExpr中所有列的类型。dtypes 返回的是Schema类型

iris.dtypes
odps.Schema {
  sepallength           float64
  sepalwidth            float64
  petallength           float64
  petalwidth            float64
  name                  string
}

列选择和增删

  • 列选择
    如果您需要从一个CollectionExpr中选取部分列,产生新的数据集,可以使用expr[columns]语法。
    iris['name', 'sepallength'].head(5)
              name  sepallength
    0  Iris-setosa          5.1
    1  Iris-setosa          4.9
    2  Iris-setosa          4.7
    3  Iris-setosa          4.6
    4  Iris-setosa          5.0
    说明

    如果需要选择的列只有一列,需要在Columns后加上逗号或者显示标记为列表,例如iris[iris.sepal_length, ]iris[[iris.sepal_length]],否则返回的将是一个Sequence对象,而不是Collection。

  • 列删除
    如果您需要在新的数据集中排除已有数据集的某些列,可使用exclude方法。
    iris.exclude('sepallength', 'petallength')[:5]
       sepalwidth  petalwidth         name
    0         3.5         0.2  Iris-setosa
    1         3.0         0.2  Iris-setosa
    2         3.2         0.2  Iris-setosa
    3         3.1         0.2  Iris-setosa
    4         3.6         0.2  Iris-setosa
    PyODPS 0.7.2版(及以上版本)支持另一种写法,即在数据集上直接排除相应的列。
    del iris['sepallength']
    del iris['petallength']
    iris[:5]
       sepalwidth  petalwidth         name
    0         3.5         0.2  Iris-setosa
    1         3.0         0.2  Iris-setosa
    2         3.2         0.2  Iris-setosa
    3         3.1         0.2  Iris-setosa
    4         3.6         0.2  Iris-setosa
  • 列增加

    如果您需要在已有Collection中添加某一列变换的结果,可以使用expr[expr, new_sequence]语法, 新增的列会作为新Collection的一部分。

    以下示例将iris中的sepalwidth列加一后重命名为sepalwidthplus1并追加到数据集末尾,形成新的数据集。
    iris[iris, (iris.sepalwidth + 1).rename('sepalwidthplus1')].head(5)
       sepallength  sepalwidth  petallength  petalwidth         name  \
    0          5.1         3.5          1.4         0.2  Iris-setosa
    1          4.9         3.0          1.4         0.2  Iris-setosa
    2          4.7         3.2          1.3         0.2  Iris-setosa
    3          4.6         3.1          1.5         0.2  Iris-setosa
    4          5.0         3.6          1.4         0.2  Iris-setosa
    
       sepalwidthplus1
    0              4.5
    1              4.0
    2              4.2
    3              4.1
    4              4.6

    使用expr[expr, new_sequence]语法需要注意的是,变换后的列名与原列名可能相同。如果需要与原Collection合并, 请将该列重命名。

    PyODPS 0.7.2版(及以上版本)支持直接在当前数据集中追加。
    iris['sepalwidthplus1'] = iris.sepalwidth + 1
    iris.head(5)
       sepallength  sepalwidth  petallength  petalwidth         name  \
    0          5.1         3.5          1.4         0.2  Iris-setosa
    1          4.9         3.0          1.4         0.2  Iris-setosa
    2          4.7         3.2          1.3         0.2  Iris-setosa
    3          4.6         3.1          1.5         0.2  Iris-setosa
    4          5.0         3.6          1.4         0.2  Iris-setosa
    
       sepalwidthplus1
    0              4.5
    1              4.0
    2              4.2
    3              4.1
    4              4.6
  • 同时增删列
    您也可以先将原列通过exclude方法进行排除,再将变换后的新列并入,而不必担心重名。
    iris[iris.exclude('sepalwidth'), iris.sepalwidth * 2].head(5)
       sepallength  petallength  petalwidth         name  sepalwidth
    0          5.1          1.4         0.2  Iris-setosa         7.0
    1          4.9          1.4         0.2  Iris-setosa         6.0
    2          4.7          1.3         0.2  Iris-setosa         6.4
    3          4.6          1.5         0.2  Iris-setosa         6.2
    4          5.0          1.4         0.2  Iris-setosa         7.2
    PyODPS 0.7.2版(及以上版本)支持直接在当前数据集上覆盖的操作,写法如下。
    iris['sepalwidth'] = iris.sepalwidth * 2
    iris.head(5)
       sepallength  sepalwidth  petallength  petalwidth         name
    0          5.1         7.0          1.4         0.2  Iris-setosa
    1          4.9         6.0          1.4         0.2  Iris-setosa
    2          4.7         6.4          1.3         0.2  Iris-setosa
    3          4.6         6.2          1.5         0.2  Iris-setosa
    4          5.0         7.2          1.4         0.2  Iris-setosa
    以创建新Collection的方式实现增删列的另一种方法是调用select,将需要选择的列作为参数输入。如果您需要重命名,可以使用keyword参数输入,并将新的列名作为参数名。
    iris.select('name', sepalwidthminus1=iris.sepalwidth - 1).head(5)
              name  sepalwidthminus1
    0  Iris-setosa               2.5
    1  Iris-setosa               2.0
    2  Iris-setosa               2.2
    3  Iris-setosa               2.1
    4  Iris-setosa               2.6
    您也可以传入一个Lambda表达式,它接收的参数为上一步的运算结果。在执行时,PyODPS会检查这些Lambda表达式,传入上一步生成的Collection并将其替换为正确的列。
    iris['name', 'petallength'][[lambda x: x.name]].head(5)
              name
    0  Iris-setosa
    1  Iris-setosa
    2  Iris-setosa
    3  Iris-setosa
    4  Iris-setosa
    PyODPS 0.7.2版(及以上版本)支持对数据进行条件赋值。
    iris[iris.sepallength > 5.0, 'sepalwidth'] = iris.sepalwidth * 2
    iris.head(5)
       sepallength  sepalwidth  petallength  petalwidth         name
    0          5.1        14.0          1.4         0.2  Iris-setosa
    1          4.9         6.0          1.4         0.2  Iris-setosa
    2          4.7         6.4          1.3         0.2  Iris-setosa
    3          4.6         6.2          1.5         0.2  Iris-setosa
    4          5.0         7.2          1.4         0.2  Iris-setosa

引入常数和随机数

  • DataFrame支持在Collection中追加一列常数。追加常数需要使用Scalar ,引入时需要手动指定列名。
    from odps.df import Scalar
    iris[iris, Scalar(1).rename('id')][:5]
       sepallength  sepalwidth  petallength  petalwidth         name  id
    0          5.1         3.5          1.4         0.2  Iris-setosa   1
    1          4.9         3.0          1.4         0.2  Iris-setosa   1
    2          4.7         3.2          1.3         0.2  Iris-setosa   1
    3          4.6         3.1          1.5         0.2  Iris-setosa   1
    4          5.0         3.6          1.4         0.2  Iris-setosa   1
    如果需要指定一个空值列,您可以使用NullScalar,但需要提供字段类型。
    from odps.df import NullScalar
    iris[iris, NullScalar('float').rename('fid')][:5]
       sepal_length  sepal_width  petal_length  petal_width     category   fid
    0           5.1          3.5           1.4          0.2  Iris-setosa  None
    1           4.9          3.0           1.4          0.2  Iris-setosa  None
    2           4.7          3.2           1.3          0.2  Iris-setosa  None
    3           4.6          3.1           1.5          0.2  Iris-setosa  None
    4           5.0          3.6           1.4          0.2  Iris-setosa  None
    在PyODPS 0.7.12(及以上版本)中,引入了简化写法。
    iris['id'] = 1
    iris
       sepallength  sepalwidth  petallength  petalwidth         name  id
    0          5.1         3.5          1.4         0.2  Iris-setosa   1
    1          4.9         3.0          1.4         0.2  Iris-setosa   1
    2          4.7         3.2          1.3         0.2  Iris-setosa   1
    3          4.6         3.1          1.5         0.2  Iris-setosa   1
    4          5.0         3.6          1.4         0.2  Iris-setosa   1
    需要注意的是,这种写法无法自动识别空值的类型,所以在增加空值列时,仍然要使用如下代码。
    iris['null_col'] = NullScalar('float')
    iris
       sepallength  sepalwidth  petallength  petalwidth         name  null_col
    0          5.1         3.5          1.4         0.2  Iris-setosa      None
    1          4.9         3.0          1.4         0.2  Iris-setosa      None
    2          4.7         3.2          1.3         0.2  Iris-setosa      None
    3          4.6         3.1          1.5         0.2  Iris-setosa      None
    4          5.0         3.6          1.4         0.2  Iris-setosa      None
  • DataFrame也支持在Collection中增加一列随机数列,该列类型为FLOAT,范围为0~1,每行数值均不同。 追加随机数列需要使用RandomScalar,参数为随机数种子,可省略。
    from odps.df import RandomScalar
    iris[iris, RandomScalar().rename('rand_val')][:5]
       sepallength  sepalwidth  petallength  petalwidth         name  rand_val
    0          5.1         3.5          1.4         0.2  Iris-setosa  0.000471
    1          4.9         3.0          1.4         0.2  Iris-setosa  0.799520
    2          4.7         3.2          1.3         0.2  Iris-setosa  0.834609
    3          4.6         3.1          1.5         0.2  Iris-setosa  0.106921
    4          5.0         3.6          1.4         0.2  Iris-setosa  0.763442

过滤数据

Collection提供了数据过滤的功能。查询sepallength大于5的数据,示例如下。
iris[iris.sepallength > 5].head(5)
   sepallength  sepalwidth  petallength  petalwidth         name
0          5.1         3.5          1.4         0.2  Iris-setosa
1          5.4         3.9          1.7         0.4  Iris-setosa
2          5.4         3.7          1.5         0.2  Iris-setosa
3          5.8         4.0          1.2         0.2  Iris-setosa
4          5.7         4.4          1.5         0.4  Iris-setosa
多种查询方式的示例:
  • 与(&)条件
    iris[(iris.sepallength < 5) & (iris['petallength'] > 1.5)].head(5)
       sepallength  sepalwidth  petallength  petalwidth             name
    0          4.8         3.4          1.6         0.2      Iris-setosa
    1          4.8         3.4          1.9         0.2      Iris-setosa
    2          4.7         3.2          1.6         0.2      Iris-setosa
    3          4.8         3.1          1.6         0.2      Iris-setosa
    4          4.9         2.4          3.3         1.0  Iris-versicolor
  • 或(|)条件
    iris[(iris.sepalwidth < 2.5) | (iris.sepalwidth > 4)].head(5)
       sepallength  sepalwidth  petallength  petalwidth             name
    0          5.7         4.4          1.5         0.4      Iris-setosa
    1          5.2         4.1          1.5         0.1      Iris-setosa
    2          5.5         4.2          1.4         0.2      Iris-setosa
    3          4.5         2.3          1.3         0.3      Iris-setosa
    4          5.5         2.3          4.0         1.3  Iris-versicolor
    说明 与和或条件必须使用&|,不能使用andor
  • 非(~)条件
    iris[~(iris.sepalwidth > 3)].head(5)
       sepallength  sepalwidth  petallength  petalwidth         name
    0          4.9         3.0          1.4         0.2  Iris-setosa
    1          4.4         2.9          1.4         0.2  Iris-setosa
    2          4.8         3.0          1.4         0.1  Iris-setosa
    3          4.3         3.0          1.1         0.1  Iris-setosa
    4          5.0         3.0          1.6         0.2  Iris-setosa
  • 显式调用filter方法,提供多个与条件。
    iris.filter(iris.sepalwidth > 3.5, iris.sepalwidth < 4).head(5)
       sepallength  sepalwidth  petallength  petalwidth         name
    0          5.0         3.6          1.4         0.2  Iris-setosa
    1          5.4         3.9          1.7         0.4  Iris-setosa
    2          5.4         3.7          1.5         0.2  Iris-setosa
    3          5.4         3.9          1.3         0.4  Iris-setosa
    4          5.7         3.8          1.7         0.3  Iris-setosa
  • 对于连续的操作,使用Lambda表达式。
    iris[iris.sepalwidth > 3.8]['name', lambda x: x.sepallength + 1]
              name  sepallength
    0  Iris-setosa          6.4
    1  Iris-setosa          6.8
    2  Iris-setosa          6.7
    3  Iris-setosa          6.4
    4  Iris-setosa          6.2
    5  Iris-setosa          6.5
  • 对于Collection,如果它包含一个列是BOOLEAN类型,则可以直接使用该列作为过滤条件。
    df.dtypes
    odps.Schema {
      a boolean
      b int64
    }
    df[df.a]
          a  b
    0  True  1
    1  True  3
    因此,对Collection取单个Sequence的操作时,只有BOOLEAN列是合法的,即对Collection作过滤操作。
    df[df.a, ]       # 取列操作。
    df[[df.a]]       # 取列操作。
    df.select(df.a)  # 显式取列。
    df[df.a]         # a列是boolean列,执行过滤操作。
    df.a             # 取单列。
    df['a']          # 取单列。
  • 同时,您可以使用Pandas中的query方法,通过查询语句做数据的筛选,在表达式中直接使用列名如sepallength进行操作。在查询语句中,&and都表示与操作,|or都表示或操作。
    iris.query("(sepallength < 5) and (petallength > 1.5)").head(5)
       sepallength  sepalwidth  petallength  petalwidth             name
    0          4.8         3.4          1.6         0.2      Iris-setosa
    1          4.8         3.4          1.9         0.2      Iris-setosa
    2          4.7         3.2          1.6         0.2      Iris-setosa
    3          4.8         3.1          1.6         0.2      Iris-setosa
    4          4.9         2.4          3.3         1.0  Iris-versicolor
    当表达式中需要使用到本地变量时,需要在该变量前加一个@前缀。
    var = 4
    iris.query("(iris.sepalwidth < 2.5) | (sepalwidth > @var)").head(5)
       sepallength  sepalwidth  petallength  petalwidth             name
    0          5.7         4.4          1.5         0.4      Iris-setosa
    1          5.2         4.1          1.5         0.1      Iris-setosa
    2          5.5         4.2          1.4         0.2      Iris-setosa
    3          4.5         2.3          1.3         0.3      Iris-setosa
    4          5.5         2.3          4.0         1.3  Iris-versicolor
    目前query支持的语法,如下表所示。
    语法 说明
    name 没有@前缀的都当做列名处理,有前缀的会获取本地变量。
    operator 支持部分运算符:+-*///%**==!=<<=>>=innot in
    bool 与或非操作,其中&and表示与,|or表示或。
    attribute 取对象属性。
    index, slice, subscript 切片操作。

并列多行输出

对于LIST及MAP类型的列,explode方法会将该列转换为多行输出。您也可以使用apply方法实现多行输出。为了进行聚合等操作,常常需要将这些输出和原表中的列合并。此时可以使用DataFrame提供的并列多行输出功能, 写法为将多行输出函数生成的集合与原集合中的列名一起映射。

并列多行输出的示例如下。
df
   id         a             b
0   1  [a1, b1]  [a2, b2, c2]
1   2      [c1]      [d2, e2]
df[df.id, df.a.explode(), df.b]
   id   a             b
0   1  a1  [a2, b2, c2]
1   1  b1  [a2, b2, c2]
2   2  c1      [d2, e2]
df[df.id, df.a.explode(), df.b.explode()]
   id   a   b
0   1  a1  a2
1   1  a1  b2
2   1  a1  c2
3   1  b1  a2
4   1  b1  b2
5   1  b1  c2
6   2  c1  d2
7   2  c1  e2
如果多行输出方法对某个输入不产生任何输出,默认输入行将不在最终结果中出现。如果需要在结果中出现该行,可以设置keep_nulls=True。此时,与该行并列的值将输出为空值。
df
   id         a
0   1  [a1, b1]
1   2        []
df[df.id, df.a.explode()]
   id   a
0   1  a1
1   1  b1
df[df.id, df.a.explode(keep_nulls=True)]
   id     a
0   1    a1
1   1    b1
2   2  None

使用explode方法实现并列多行输出的示例,请参见集合类型相关操作

限制条数

输出前三条数据。
iris[:3]
   sepallength  sepalwidth  petallength  petalwidth         name
0          5.1         3.5          1.4         0.2  Iris-setosa
1          4.9         3.0          1.4         0.2  Iris-setosa
2          4.7         3.2          1.3         0.2  Iris-setosa
目前对于MaxCompute SQL,后端切片不支持startstep方法,但支持limit方法。
iris.limit(3)
   sepallength  sepalwidth  petallength  petalwidth         name
0          5.1         3.5          1.4         0.2  Iris-setosa
1          4.9         3.0          1.4         0.2  Iris-setosa
2          4.7         3.2          1.3         0.2  Iris-setosa
说明 切片操作只能作用于Collection,不能作用于Sequence。