使用 BigQuery DataFrames 数据类型系统

BigQuery DataFrames 数据类型系统基于 BigQuery 数据类型构建。此设计可确保与Trusted Cloud by S3NS 数据仓库实现无缝集成和一致性,从而反映 BigQuery 中用于数据存储的内置类型。

类型映射

下表显示了 BigQuery、BigQuery DataFrames 和其他 Python 库中的等效数据类型,以及它们的支持级别:

数据类型 BigQuery BigQuery DataFrames Python 内置 PyArrow
布尔值 BOOL pandas.BooleanDtype() bool bool_()
整数 INT64 pandas.Int64Dtype() int int64()
浮点数 FLOAT64 pandas.Float64Dtype() float float64()
字符串 STRING pandas.StringDtype(storage="pyarrow") str string()
字节 BYTES pandas.ArrowDtype(pyarrow.binary()) bytes binary()
日期 DATE pandas.ArrowDtype(pyarrow.date32()) datetime.date date32()
时间 TIME pandas.ArrowDtype(pyarrow.time64("us")) datetime.time time64("us")
日期时间 DATETIME pandas.ArrowDtype(pyarrow.timestamp("us")) datetime.datetime timestamp("us")
时间戳 TIMESTAMP pandas.ArrowDtype(pyarrow.timestamp("us", tz="UTC")) Datetime.datetime,有时区 timestamp("us", tz="UTC")
数字 NUMERIC pandas.ArrowDtype(pyarrow.decimal128(38, 9)) decimal.Decimal decimal128(38, 9)
大数字 BIGNUMERIC pandas.ArrowDtype(pyarrow.decimal256(76, 38)) decimal.Decimal decimal256(76, 38)
List ARRAY<T> pandas.ArrowDtype(pyarrow.list_(T)) list[T] list_(T)
结构体 STRUCT pandas.ArrowDtype(pyarrow.struct()) dict struct()
JSON JSON pandas.ArrowDtype(pyarrow.json_(pa.string())(如果使用的是 pandas 3.0 版或更高版本以及 PyArrow 19.0 版或更高版本);否则,JSON 列将显示为 pandas.ArrowDtype(db_dtypes.JSONArrowType())。此功能处于预览版阶段。 不支持 json_()预览版
地理位置 GEOGRAPHY Geopandas.array.GeometryDtype()
仅受 to_pandas() 支持。
不支持 不支持
Timedelta 不支持 pandas.ArrowDtype(pyarrow.duration("us")) datetime.timedelta duration("us")

类型转换

与本地数据搭配使用时,BigQuery DataFrames 会将数据类型转换为相应的 BigQuery DataFrames 等效类型(只要定义了类型映射),如以下示例所示:

import pandas as pd

import bigframes.pandas as bpd

s = pd.Series([pd.Timestamp("20250101")])
assert s.dtype == "datetime64[ns]"
assert bpd.read_pandas(s).dtype == "timestamp[us][pyarrow]"

当数据类型等效项之间存在差异时,PyArrow 会规定行为。在极少数情况下,当 Python 内置类型函数的行为与 PyArrow 对应函数的行为不同时,BigQuery DataFrames 通常会优先考虑 PyArrow 行为,以确保一致性。

以下代码示例使用 datetime.date + timedelta 操作来表明,与仍返回日期实例的 Python datetime 库不同,BigQuery DataFrames 遵循 PyArrow 行为,返回时间戳实例:

import datetime

import pandas as pd

import bigframes.pandas as bpd

s = pd.Series([datetime.date(2025, 1, 1)])
s + pd.Timedelta(hours=12)
# 0	2025-01-01
# dtype: object

bpd.read_pandas(s) + pd.Timedelta(hours=12)
# 0    2025-01-01 12:00:00
# dtype: timestamp[us][pyarrow]

特殊类型

以下部分介绍了 BigQuery DataFrames 使用的特殊数据类型。

JSON

在 BigQuery DataFrames 中,使用 BigQuery JSON 格式(一种轻量级标准)的列由 pandas.ArrowDtype 表示。确切的底层 Arrow 类型取决于您的库版本。旧版环境通常使用 db_dtypes.JSONArrowType() 来实现兼容性,这是一种 Arrow 扩展类型,可作为 pa.string() 的轻量级封装容器。相比之下,较新的设置(pandas 3.0 及更高版本和 PyArrow 19.0 及更高版本)会使用最新的 pa.json_(pa.string()) 表示法。

timedelta

timedelta 类型在 BigQuery 原生类型系统中没有直接对应的类型。为了管理时长数据,BigQuery DataFrames 使用 INT64 类型作为 BigQuery 表中的底层存储格式。您可以预期,计算结果与使用 pandas 库执行等效操作时获得的预期结果一致。

您可以将 timedelta 值直接加载到 BigQuery DataFrames 和 Series 对象中,如以下示例所示:

import pandas as pd

import bigframes.pandas as bpd

s = pd.Series([pd.Timedelta("1s"), pd.Timedelta("2m")])
bpd.read_pandas(s)
# 0    0 days 00:00:01
# 1    0 days 00:02:00
# dtype: duration[us][pyarrow]

与 pandas 不同,BigQuery DataFrames 仅支持精确到微秒的 timedelta 值。如果您的数据包含纳秒,您必须将其舍入,以免出现潜在的异常,如以下示例所示:

import pandas as pd

s = pd.Series([pd.Timedelta("999ns")])
bpd.read_pandas(s.dt.round("us"))
# 0    0 days 00:00:00.000001
# dtype: duration[us][pyarrow]

您可以使用 bigframes.pandas.to_timedelta 函数将 BigQuery DataFrames Series 对象转换为 timedelta 类型,如以下示例所示:

import bigframes.pandas as bpd

bpd.to_timedelta([1, 2, 3], unit="s")
# 0    0 days 00:00:01
# 1    0 days 00:00:02
# 2    0 days 00:00:03
# dtype: duration[us][pyarrow]

将包含 timedelta 值的数据加载到 BigQuery 表中时,这些值会转换为微秒并存储在 INT64 列中。为了保留类型信息,BigQuery DataFrames 会在这些列的说明中附加 #microseconds 字符串。某些操作(例如 SQL 查询执行和 UDF 调用)不会保留列说明,并且在这些操作完成后,timedelta 类型信息会丢失。

复合类型工具

对于某些复合类型,BigQuery DataFrames 提供了相关工具,可让您访问和处理这些类型中的元素值。

列表访问器

ListAccessor 对象可帮助您使用 Series 对象的 list 属性对每个列表元素执行操作,如下例所示:

import bigframes.pandas as bpd

s = bpd.Series([[1, 2, 3], [4, 5], [6]])  # dtype: list<item: int64>[pyarrow]

# Access the first elements of each list
s.list[0]
# 0    1
# 1    4
# 2    6
# dtype: Int64

# Get the lengths of each list
s.list.len()
# 0    3
# 1    2
# 2    1
# dtype: Int64

结构体访问器

StructAccessor 对象可以访问和处理一系列结构体中的字段。API 访问器对象为 series.struct,如以下示例所示:

import bigframes.pandas as bpd

structs = [
    {"id": 101, "category": "A"},
    {"id": 102, "category": "B"},
    {"id": 103, "category": "C"},
]
s = bpd.Series(structs)
# Get the 'id' field of each struct
s.struct.field("id")
# 0    101
# 1    102
# 2    103
# Name: id, dtype: Int64

如果您计划访问的 struct 字段与其他 Series 属性没有歧义,则可以跳过调用 struct,如以下示例所示:

import bigframes.pandas as bpd

structs = [
    {"id": 101, "category": "A"},
    {"id": 102, "category": "B"},
    {"id": 103, "category": "C"},
]
s = bpd.Series(structs)

# not explicitly using the "struct" property
s.id
# 0    101
# 1    102
# 2    103
# Name: id, dtype: Int64

不过,最佳做法是使用 struct 访问字段,因为这样可使您的代码更易于理解且不易出错。

字符串访问器

您可以使用 Series 对象上的 str 属性访问 StringAccessor 对象,如以下示例所示:

import bigframes.pandas as bpd

s = bpd.Series(["abc", "de", "1"])  # dtype: string[pyarrow]

# Get the first character of each string
s.str[0]
# 0    a
# 1    d
# 2    1
# dtype: string

# Check whether there are only alphabetic characters in each string
s.str.isalpha()
# 0     True
# 1     True
# 2     False
# dtype: boolean

# Cast the alphabetic characters to their upper cases for each string
s.str.upper()
# 0    ABC
# 1     DE
# 2      1
# dtype: string

地理位置访问器

BigQuery DataFrames 提供一个 GeographyAccessor 对象,该对象与 GeoPandas 库提供的 GeoSeries 结构共享类似的 API。您可以使用 Series 对象的 geo 属性调用 GeographyAccessor 对象,如以下示例所示:

from shapely.geometry import Point

import bigframes.pandas as bpd

s = bpd.Series([Point(1, 0), Point(2, 1)])  # dtype: geometry

s.geo.y
# 0    0.0
# 1    1.0
# dtype: Float64

后续步骤