全部產品
Search
文件中心

:排序、去重、採樣、資料變換

更新時間:Feb 28, 2024

您可以對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

    結果顯示,name1name2兩組均按組中的最值進行了縮放。

  • 使用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

    您也可以使用ffillbfill函數簡化代碼。ffill等價於fillna(method=’ffill’)bfill等價於fillna(method=’bfill’)