全部產品
Search
文件中心

:Collection

更新時間:Jun 19, 2024

DataFrame中所有二維資料集上的操作都屬於CollectionExpr,可視為一張MaxCompute表或一張電子錶單,DataFrame對象也是CollectionExpr的特例。CollectionExpr中包含針對二維資料集的列操作、篩選、變換等大量操作。

前提條件

您需要提前完成以下步驟,用於操作本文中的樣本:

擷取類型

dtypes可以用來擷取CollectionExpr中所有列的類型,dtypes 返回的是Schema類型 ,程式碼範例如下。

print(iris.dtypes)

返回結果:

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

列選擇和增刪

列選擇

如果您需要從一個CollectionExpr中選取部分列,產生新的資料集,可以使用expr[columns]文法,程式碼範例如下。

print(iris['name', 'sepallength'].head(5))

返回結果:

          name  sepallength
0  Iris-setosa          4.9
1  Iris-setosa          4.7
2  Iris-setosa          4.6
3  Iris-setosa          5.0
4  Iris-setosa          5.4
說明

如果只需要選取一列,需要在Columns後加上逗號或者顯示標記為列表,例如iris[iris.sepallength, ]iris[[iris.sepallength]],否則返回的將是一個Sequence對象,而不是Collection。

列刪除

  • 如果您需要在新的資料集中排除已有資料集的某些列,可使用exclude方法,程式碼範例如下。

    print(iris.exclude('sepallength', 'petallength')[:5].head(5))

    返回結果:

       sepalwidth  petalwidth         name
    0         3.0         0.2  Iris-setosa
    1         3.2         0.2  Iris-setosa
    2         3.1         0.2  Iris-setosa
    3         3.6         0.2  Iris-setosa
    4         3.9         0.4  Iris-setosa
  • PyODPS 0.7.2版(及以上版本)支援另一種寫法,即在資料集上直接排除相應的列。程式碼範例如下。

    del iris['sepallength']
    del iris['petallength']
    print(iris[:5].head(5))

    返回結果:

       sepalwidth  petalwidth         name
    0         3.0         0.2  Iris-setosa
    1         3.2         0.2  Iris-setosa
    2         3.1         0.2  Iris-setosa
    3         3.6         0.2  Iris-setosa
    4         3.9         0.4  Iris-setosa

列增加

  • 如果您需要在已有Collection中添加某一列變換的結果,可以使用expr[expr, new_sequence]文法, 新增的列會作為新Collection的一部分。

    樣本:將iris中的sepalwidth列加一後重新命名為sepalwidthplus1並追加到資料集末尾,形成新的資料集。 代碼如下:

    print(iris[iris, (iris.sepalwidth + 1).rename('sepalwidthplus1')].head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name  \
    0          4.9         3.0          1.4         0.2  Iris-setosa   
    1          4.7         3.2          1.3         0.2  Iris-setosa   
    2          4.6         3.1          1.5         0.2  Iris-setosa   
    3          5.0         3.6          1.4         0.2  Iris-setosa   
    4          5.4         3.9          1.7         0.4  Iris-setosa   
    
       sepalwidthplus1  
    0              4.0  
    1              4.2  
    2              4.1  
    3              4.6  
    4              4.9  
  • 使用expr[expr, new_sequence]文法需要注意,變換後的列名與原列名可能相同。如果需要與原Collection合并, 請將該列重新命名。PyODPS 0.7.2版(及以上版本)支援直接在當前資料集中追加,程式碼範例如下。

    iris['sepalwidthplus1'] = iris.sepalwidth + 1
    print(iris.head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name  \
    0          4.9         3.0          1.4         0.2  Iris-setosa   
    1          4.7         3.2          1.3         0.2  Iris-setosa   
    2          4.6         3.1          1.5         0.2  Iris-setosa   
    3          5.0         3.6          1.4         0.2  Iris-setosa   
    4          5.4         3.9          1.7         0.4  Iris-setosa  
    
       sepalwidthplus1  
    0              4.0  
    1              4.2  
    2              4.1  
    3              4.6  
    4              4.9 

同時增刪列

  • 您可以先將原列通過exclude方法進行排除,再將變換後的新列併入,而不必擔心重名。程式碼範例如下。

    print(iris[iris.exclude('sepalwidth'), iris.sepalwidth * 2].head(5))

    返回結果:

       sepallength  petallength  petalwidth         name  sepalwidth
    0          4.9          1.4         0.2  Iris-setosa         6.0
    1          4.7          1.3         0.2  Iris-setosa         6.4
    2          4.6          1.5         0.2  Iris-setosa         6.2
    3          5.0          1.4         0.2  Iris-setosa         7.2
    4          5.4          1.7         0.4  Iris-setosa         7.8
  • PyODPS 0.7.2版(及以上版本)支援直接在當前資料集上覆蓋的操作。程式碼範例如下。

    iris['sepalwidth'] = iris.sepalwidth * 2
    print(iris.head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name
    0          4.9         6.0          1.4         0.2  Iris-setosa
    1          4.7         6.4          1.3         0.2  Iris-setosa
    2          4.6         6.2          1.5         0.2  Iris-setosa
    3          5.0         7.2          1.4         0.2  Iris-setosa
    4          5.4         7.8          1.7         0.4  Iris-setosa
  • 以建立新Collection的方式實現增刪列的另一種方法是調用select,將需要選擇的列作為參數輸入。如果您需要重新命名,可以使用keyword參數輸入,並將新的列名作為參數名。程式碼範例如下。

    print(iris.select('name', sepalwidthminus1=iris.sepalwidth - 1).head(5))

    返回結果:

              name  sepalwidthminus1
    0  Iris-setosa               2.0
    1  Iris-setosa               2.2
    2  Iris-setosa               2.1
    3  Iris-setosa               2.6
    4  Iris-setosa               2.9
  • 您也可以傳入一個Lambda運算式,它接收的參數為上一步的運算結果。在執行時,PyODPS會檢查這些Lambda運算式,傳入上一步產生的Collection並將其替換為正確的列。 程式碼範例如下。

    print(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
    print(iris.head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name
    0          4.9         3.0          1.4         0.2  Iris-setosa
    1          4.7         3.2          1.3         0.2  Iris-setosa
    2          4.6         3.1          1.5         0.2  Iris-setosa
    3          5.0         3.6          1.4         0.2  Iris-setosa
    4          5.4         7.8          1.7         0.4  Iris-setosa

引入常數和隨機數

引入常數

  • DataFrame支援在Collection中追加一列常數。追加常數需要使用 Scalar,引入時需要手動指定列名。 程式碼範例如下。

    from odps.df import Scalar
    print(iris[iris, Scalar(1).rename('id')][:5].head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name  id
    0          4.9         3.0          1.4         0.2  Iris-setosa   1
    1          4.7         3.2          1.3         0.2  Iris-setosa   1
    2          4.6         3.1          1.5         0.2  Iris-setosa   1
    3          5.0         3.6          1.4         0.2  Iris-setosa   1
    4          5.4         3.9          1.7         0.4  Iris-setosa   1
  • 如果需要指定一個空值列,您可以使用NullScalar,但需要提供欄位類型。 程式碼範例如下。

    from odps.df import NullScalar
    print(iris[iris, NullScalar('float').rename('fid')][:5].head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name   fid
    0          4.9         3.0          1.4         0.2  Iris-setosa  None
    1          4.7         3.2          1.3         0.2  Iris-setosa  None
    2          4.6         3.1          1.5         0.2  Iris-setosa  None
    3          5.0         3.6          1.4         0.2  Iris-setosa  None
    4          5.4         3.9          1.7         0.4  Iris-setosa  None
  • 在PyODPS 0.7.12(及以上版本)中,引入了簡化寫法。 程式碼範例如下。

    iris['id'] = 1
    print(iris.head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name  id
    0          4.9         3.0          1.4         0.2  Iris-setosa   1
    1          4.7         3.2          1.3         0.2  Iris-setosa   1
    2          4.6         3.1          1.5         0.2  Iris-setosa   1
    3          5.0         3.6          1.4         0.2  Iris-setosa   1
    4          5.4         3.9          1.7         0.4  Iris-setosa   1

    需要注意的是,這種寫法無法自動識別空值的類型,所以在增加空值列時,仍然要使用如下代碼。

    iris['null_col'] = NullScalar('float')
    print(iris.head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name null_col
    0          4.9         3.0          1.4         0.2  Iris-setosa     None
    1          4.7         3.2          1.3         0.2  Iris-setosa     None
    2          4.6         3.1          1.5         0.2  Iris-setosa     None
    3          5.0         3.6          1.4         0.2  Iris-setosa     None
    4          5.4         3.9          1.7         0.4  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          4.9         3.0          1.4         0.2  Iris-setosa  0.000471
1          4.7         3.2          1.3         0.2  Iris-setosa  0.799520
2          4.6         3.1          1.5         0.2  Iris-setosa  0.834609
3          5.0         3.6          1.4         0.2  Iris-setosa  0.106921
4          5.4         3.9          1.7         0.4  Iris-setosa  0.763442

過濾資料

Collection提供了資料過濾的功能。支援使用與(&) 、或(|)、非(~)、filter、Lambda運算式,及其他多種查詢方式對資料進行過濾。

  • 樣本1:查詢sepallength大於5的資料。

    print(iris[iris.sepallength > 5].head(5))

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name
    0          5.4         3.9          1.7         0.4  Iris-setosa
    1          5.4         3.7          1.5         0.2  Iris-setosa
    2          5.8         4.0          1.2         0.2  Iris-setosa
    3          5.7         4.4          1.5         0.4  Iris-setosa
    4          5.4         3.9          1.3         0.4  Iris-setosa
  • 樣本2:與(&)條件 。

    print(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
  • 樣本3:或(|)條件 。

    print(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

  • 樣本4:非(~)條件 。

    print(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
  • 樣本5:顯式調用filter方法,提供多個與條件。

    print(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
  • 樣本6:對於連續的操作,使用Lambda運算式。

    print(iris[iris.sepalwidth > 3.8]['name', lambda x: x.sepallength + 1].head(5))

    返回結果:

              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
  • 樣本7:對於Collection,如果它包含一個列是BOOLEAN類型,則可以直接使用該列作為過濾條件。

    # 查詢Schema
    print(df.dtypes)
    # 返回結果
    odps.Schema {
      a boolean
      b int64
    }
    
    # a列為boolean類型,執行過濾操作
    print(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']          # 取單列。
  • 樣本8:使用Pandas中的query方法,通過查詢語句做資料的篩選,在運算式中直接使用列名(如sepallength)進行操作。在查詢語句中,&and都表示與操作,|or都表示或操作。

    print(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
    print(iris.query("(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提供的並列多行輸出功能, 寫法為將多行輸出函數產生的集合與原集合中的列名一起映射。 並列多行輸出的樣本如下。

    • 查詢樣本資料:

      print(df)

      返回結果:

         id         a             b
      0   1  [a1, b1]  [a2, b2, c2]
      1   2      [c1]      [d2, e2]
    • 樣本1:

      print(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]
    • 樣本2:

      print(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。此時,與該行並列的值將輸出為空白值。樣本如下。

    • 查詢樣本資料:

      print(df)

      返回結果:

         id         a
      0   1  [a1, b1]
      1   2        []
    • 樣本1:

      print(df[df.id, df.a.explode()])

      返回結果:

         id   a
      0   1  a1
      1   1  b1
    • 樣本2:

      print(df[df.id, df.a.explode(keep_nulls=True)])

      返回結果:

         id     a
      0   1    a1
      1   1    b1
      2   2  None
  • 使用explode方法實現並列多行輸出的樣本,請參見集合類型相關操作

限制條數

  • 輸出前三條資料。

    print(iris[:3].execute())

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name
    0          4.9         3.0          1.4         0.2  Iris-setosa
    1          4.7         3.2          1.3         0.2  Iris-setosa
    2          4.6         3.1          1.5         0.2  Iris-setosa
  • 目前對於MaxCompute SQL,後端切片不支援startstep方法,但支援limit方法。

    print(iris.limit(3).execute())

    返回結果:

       sepallength  sepalwidth  petallength  petalwidth         name
    0          4.9         3.0          1.4         0.2  Iris-setosa
    1          4.7         3.2          1.3         0.2  Iris-setosa
    2          4.6         3.1          1.5         0.2  Iris-setosa
    說明

    切片操作只能作用於Collection,不能作用於Sequence。