資料處理

與濾出或轉換陣列及表格中資料相關的食譜。

請參閱 運算函數,以取得所有可用的運算函數的完整清單

計算陣列的平均值/最小值/最大值

Arrow 提供可套用於陣列的運算函數。這些運算函數會透過 pyarrow.compute 模組公開。

假設有一個陣列,其中有 100 個數字,從 0 到 99

print(f"{arr[0]} .. {arr[-1]}")
0 .. 99

我們可以使用 pyarrow.compute.mean() 函數來計算 平均值

import pyarrow.compute as pc

mean = pc.mean(arr)
print(mean)
49.5

並使用 pyarrow.compute.min_max() 函數來計算 最小值最大值

import pyarrow.compute as pc

min_max = pc.min_max(arr)
print(min_max)
[('min', 0), ('max', 99)]

計算元素出現的次數

Arrow 提供可套用於陣列的運算函數,這些運算函數會透過 pyarrow.compute 模組公開。

假設有一個陣列,其中包含 0 到 9 的所有數字,每個數字重複 10 次

print(f"LEN: {len(nums_arr)}, MIN/MAX: {nums_arr[0]} .. {nums_arr[-1]}")
LEN: 100, MIN/MAX: 0 .. 9

我們可以使用 pyarrow.compute.value_counts() 函數來計算陣列中所有條目的出現次數

import pyarrow.compute as pc

counts = pc.value_counts(nums_arr)
for pair in counts:
    print(pair)
[('values', 0), ('counts', 10)]
[('values', 1), ('counts', 10)]
[('values', 2), ('counts', 10)]
[('values', 3), ('counts', 10)]
[('values', 4), ('counts', 10)]
[('values', 5), ('counts', 10)]
[('values', 6), ('counts', 10)]
[('values', 7), ('counts', 10)]
[('values', 8), ('counts', 10)]
[('values', 9), ('counts', 10)]

將算術函數套用於陣列。

pyarrow.compute 中的運算函數還包含常見的轉換,例如算術函數。

假設有一個陣列,其中有 100 個數字,從 0 到 99

print(f"{arr[0]} .. {arr[-1]}")
0 .. 99

我們可以使用 pyarrow.compute.multiply() 函數將所有值乘以 2

import pyarrow.compute as pc

doubles = pc.multiply(arr, 2)
print(f"{doubles[0]} .. {doubles[-1]}")
0 .. 198

將表格附加至現有表格

如果你的資料分散在兩個不同的表格中,則可以將它們的列串接成一個單一表格。

如果我們有分散在兩個不同表格中的奧斯卡提名名單

import pyarrow as pa

oscar_nominations_1 = pa.table([
  ["Meryl Streep", "Katharine Hepburn"],
  [21, 12]
], names=["actor", "nominations"])

oscar_nominations_2 = pa.table([
  ["Jack Nicholson", "Bette Davis"],
  [12, 10]
], names=["actor", "nominations"])

我們可以使用 pyarrow.concat_tables() 將它們合併成一個單一表格

oscar_nominations = pa.concat_tables([oscar_nominations_1,
                                      oscar_nominations_2])
print(oscar_nominations)
pyarrow.Table
actor: string
nominations: int64
----
actor: [["Meryl Streep","Katharine Hepburn"],["Jack Nicholson","Bette Davis"]]
nominations: [[21,12],[12,10]]

注意

預設情況下,附加兩個表格是一個零複製操作,不需要複製或重寫資料。由於表格是由 pyarrow.ChunkedArray 所組成,結果將會是一個具有多個區塊的表格,每個區塊指向已經附加的原始資料。在某些情況下,Arrow 可能必須將資料從一種型態轉換成另一種型態(如果 promote=True)。在這種情況下,資料將需要被複製,並且會產生額外的成本。

將欄位新增至現有表格

如果你有一個表格,則可以使用 pyarrow.Table.append_column() 來延伸它的欄位

假設我們有一個表格,其中包含每個女演員的奧斯卡提名

import pyarrow as pa

oscar_nominations = pa.table([
  ["Meryl Streep", "Katharine Hepburn"],
  [21, 12]
], names=["actor", "nominations"])

print(oscar_nominations)
pyarrow.Table
actor: string
nominations: int64
----
actor: [["Meryl Streep","Katharine Hepburn"]]
nominations: [[21,12]]

可以使用 pyarrow.Table.append_column() 附加一個額外的欄位來追蹤提名得獎的年份

oscar_nominations = oscar_nominations.append_column(
  "wonyears",
  pa.array([
    [1980, 1983, 2012],
    [1934, 1968, 1969, 1982]
  ])
)

print(oscar_nominations)
pyarrow.Table
actor: string
nominations: int64
wonyears: list<item: int64>
  child 0, item: int64
----
actor: [["Meryl Streep","Katharine Hepburn"]]
nominations: [[21,12]]
wonyears: [[[1980,1983,2012],[1934,1968,1969,1982]]]

取代現有表格中的欄位

如果你有一個表格,則可以使用 pyarrow.Table.set_column() 來取代現有的欄位

假設我們有一個表格,其中包含某家超市在特定一天所銷售商品的資訊。

import pyarrow as pa

sales_data = pa.table([
  ["Potato", "Bean", "Cucumber", "Eggs"],
  [21, 12, 10, 30]
], names=["item", "amount"])

print(sales_data)
pyarrow.Table
item: string
amount: int64
----
item: [["Potato","Bean","Cucumber","Eggs"]]
amount: [[21,12,10,30]]

可以替換現有索引 1 中的欄位 amount,以使用 pyarrow.Table.set_column() 更新銷售數字。

new_sales_data = sales_data.set_column(
  1,
  "new_amount",
  pa.array([30, 20, 15, 40])
)

print(new_sales_data)
pyarrow.Table
item: string
new_amount: int64
----
item: [["Potato","Bean","Cucumber","Eggs"]]
new_amount: [[30,20,15,40]]

分組表格

如果你有一個需要透過特定鍵分組的表格,可以使用 pyarrow.Table.group_by(),後接聚集運算 pyarrow.TableGroupBy.aggregate()。在此處深入了解分組運算。

例如,假設我們有一些資料搭配特定的鍵及其所關聯的值。而且我們想要透過這些鍵分組資料並套用聚集函式(像是求和)來評估每個唯一鍵有多少個項目。

import pyarrow as pa

table = pa.table([
     pa.array(["a", "a", "b", "b", "c", "d", "e", "c"]),
     pa.array([11, 20, 3, 4, 5, 1, 4, 10]),
    ], names=["keys", "values"])

print(table)
pyarrow.Table
keys: string
values: int64
----
keys: [["a","a","b","b","c","d","e","c"]]
values: [[11,20,3,4,5,1,4,10]]

現在讓我們套用分組運算。表格將按照欄位 key 分組,而且會對欄位 values 套用聚集運算 sum。請注意,聚集運算會與欄位名稱配對。

aggregated_table = table.group_by("keys").aggregate([("values", "sum")])

print(aggregated_table)
pyarrow.Table
keys: string
values_sum: int64
----
keys: [["a","b","c","d","e"]]
values_sum: [[31,7,15,1,4]]

如果你仔細觀察,新的表格會將聚集欄位傳回為 values_sum,是由欄位名稱和聚集運算名稱所組成。

聚集運算可以和選項一起套用。讓我們來看看一個案例,我們的資料集中包含 Null 值,但是我們想要計算唯一群組的數量時不包含這些 Null 值。

可以像下面這樣形成一個範例資料集。

import pyarrow as pa

table = pa.table([
      pa.array(["a", "a", "b", "b", "b", "c", "d", "d", "e", "c"]),
      pa.array([None, 20, 3, 4, 5, 6, 10, 1, 4, None]),
      ], names=["keys", "values"])

print(table)
pyarrow.Table
keys: string
values: int64
----
keys: [["a","a","b","b","b","c","d","d","e","c"]]
values: [[null,20,3,4,5,6,10,1,4,null]]

讓我們搭配選項來套用聚集運算 count,藉此排除 Null 值。

import pyarrow.compute as pc

grouped_table = table.group_by("keys").aggregate(
  [("values",
  "count",
  pc.CountOptions(mode="only_valid"))]
)

print(grouped_table)
pyarrow.Table
keys: string
values_count: int64
----
keys: [["a","b","c","d","e"]]
values_count: [[1,3,1,2,1]]

排序表格

讓我們討論如何排序表格。我們可以根據特定欄位的值來排序表格。資料可以按順序 升冪降冪 排序。

準備資料;

import pyarrow as pa

table = pa.table([
      pa.array(["a", "a", "b", "b", "b", "c", "d", "d", "e", "c"]),
      pa.array([15, 20, 3, 4, 5, 6, 10, 1, 14, 123]),
      ], names=["keys", "values"])

print(table)
pyarrow.Table
keys: string
values: int64
----
keys: [["a","a","b","b","b","c","d","d","e","c"]]
values: [[15,20,3,4,5,6,10,1,14,123]]

然後套用 pyarrow.Table.sort_by() 進行排序;

sorted_table = table.sort_by([("values", "ascending")])

print(sorted_table)
pyarrow.Table
keys: string
values: int64
----
keys: [["d","b","b","b","c","d","e","a","a","c"]]
values: [[1,3,4,5,6,10,14,15,20,123]]

在陣列中搜尋與謂詞相符的值

如果您必須在 Arrow 陣列中搜尋與謂詞相符的值,pyarrow.compute 模組會提供多種方法來用於尋找您正在找尋的值。

例如,給定包含 0 到 9 數字的陣列,如果我們只想要尋找大於 5 的值,我們可以使用 pyarrow.compute.greater() 方法並取回符合我們謂詞的元素

import pyarrow as pa
import pyarrow.compute as pc

arr = pa.array(range(10))
gtfive = pc.greater(arr, 5)

print(gtfive.to_string())
[
  false,
  false,
  false,
  false,
  false,
  false,
  true,
  true,
  true,
  true
]

此外,我們可以使用 pyarrow.compute.filter() 來過濾陣列,只取得符合我們謂詞的項目

filtered_array = pc.filter(arr, gtfive)
print(filtered_array)
[
  6,
  7,
  8,
  9
]

使用遮罩過濾陣列

在許多情況下,當您在陣列中搜尋某個東西時,您將會得到一個告訴您搜尋結果在哪些位置與值相符的遮罩。

例如在一個有四個項目的陣列中,我們可能會只與第一個和最後一個項目相符的遮罩

import pyarrow as pa

array = pa.array([1, 2, 3, 4])
mask = pa.array([True, False, False, True])

然後我們可以根據遮罩使用 pyarrow.Array.filter() 來過濾陣列,只取回與遮罩相符的陣列中的值

filtered_array = array.filter(mask)
print(filtered_array)
[
  1,
  4
]

pyarrow.compute 中大多數的搜尋功能會產生一個遮罩作為輸出,因此您可以使用它們來過濾陣列,只留下功能搜尋到的值。

例如,我們可以使用 pyarrow.compute.equal() 來根據相等於 2 的值來過濾陣列

import pyarrow.compute as pc

filtered_array = array.filter(pc.equal(array, 2))
print(filtered_array)
[
  2
]