分类变量

分类变量

Dask DataFrame 将 categorical data 分为两种类型:

  • 已知的分类数据在 categories 属性上静态地(在 _meta 属性上)已知。每个分区 必须 具有与 _meta 属性上找到的相同的分类。

  • 未知的分类变量在静态上不知道类别,并且在每个分区中可能具有不同的类别。在内部,未知的分类变量通过在 _meta 属性的类别中存在 dd.utils.UNKNOWN_CATEGORIES 来表示。由于大多数 DataFrame 操作会传播类别,已知/未知状态应通过操作传播(类似于 NaN 的传播方式)。

对于指定为描述的元数据(上述选项2),会创建未知的分类。

某些操作仅对已知的分类数据有效。例如,df.col.cat.categories 只有在 df.col 具有已知类别时才能工作,因为分类映射仅在已知分类数据的元数据中静态已知。

可以使用分类访问器上的 known 属性找到分类列的已知/未知状态:

>>> ddf.col.cat.known
False

此外,未知的分类可以转换为已知的使用 .cat.as_known()。 如果你有一个DataFrame中有多个分类列,你可能更想使用 df.categorize(columns=...),这将把所有指定的列转换为已知的分类。 由于获取类别需要完整扫描数据,使用 df.categorize() 比为每列调用 .cat.as_known() 更高效(这将导致多次扫描):

>>> col_known = ddf.col.cat.as_known()  # use for single column
>>> col_known.cat.known
True
>>> ddf_known = ddf.categorize()        # use for multiple columns
>>> ddf_known.col.cat.known
True

要将已知的分类转换为未知的分类,还可以使用 .cat.as_unknown() 方法。这不需要计算,因为它只是元数据的变化。

非分类列可以通过几种不同的方式转换为分类列:

# astype operates lazily, and results in unknown categoricals
ddf = ddf.astype({'mycol': 'category', ...})
# or
ddf['mycol'] = ddf.mycol.astype('category')

# categorize requires computation, and results in known categoricals
ddf = ddf.categorize(columns=['mycol', ...])

此外,使用 Pandas 0.19.2 及以上版本,dd.read_csvdd.read_table 可以通过将列数据类型指定为 'category' 来直接读取数据到未知的分类列中:

>>> ddf = dd.read_csv(..., dtype={col_name: 'category'})

此外,使用 Pandas 0.21.0 及以上版本,dd.read_csvdd.read_table 可以通过指定 pd.api.types.CategoricalDtype 的实例,直接将数据读入 已知 的分类数据类型中:

>>> dtype = {'col': pd.api.types.CategoricalDtype(['a', 'b', 'c'])}
>>> ddf = dd.read_csv(..., dtype=dtype)

如果你写入和读取parquet文件,Dask会忘记已知的分类。这是因为出于性能考虑,所有的分类都保存在每个分区中,而不是保存在parquet元数据中。可以手动加载分类:

>>> import dask.dataframe as dd
>>> import pandas as pd
>>> df = pd.DataFrame(data=list('abcaabbcc'), columns=['col'])
>>> df.col = df.col.astype('category')
>>> ddf = dd.from_pandas(df, npartitions=1)
>>> ddf.col.cat.known
True
>>> ddf.to_parquet('tmp')
>>> ddf2 = dd.read_parquet('tmp')
>>> ddf2.col.cat.known
False
>>> ddf2.col = ddf2.col.cat.set_categories(ddf2.col.head(1).cat.categories)
>>> ddf2.col.cat.known
True