类型提示Pandas DataFrame内容和列

wgmfuz8q  于 2023-04-28  发布在  其他
关注(0)|答案(4)|浏览(106)

我正在写一个返回Pandas DataFrame对象的函数。我希望有某种类型的提示这个DataFrame包含哪些列,而不仅仅是文档中的规范,因为我觉得这将使最终用户更容易阅读数据。
在编辑Python文件和编辑Jupyter Notebooks时,是否有一种方法可以输入不同工具(如Visual Studio Code和PyCharm)支持的提示DataFrame内容?
示例函数:

def generate_data(bunch, of, inputs) -> pd.DataFrame:
      """Massages the input to a nice and easy DataFrame.

      :return:
           DataFrame with columns a(int), b(float), c(string), d(us dollars as float)
      """
olqngx59

olqngx591#

据我所知,仅仅使用核心Python和pandas是无法做到这一点的。
我推荐使用pandera,它有更广泛的作用域,但是类型检查dataframe列类型是它的功能之一。
pandera也可以使用in conjunctionpydantic,而VS Code (via Pylance)Pycharm插件也可以使用。

rekjcdws

rekjcdws2#

到目前为止(2023年4月),pandasDataFrame的强类型最强大的项目是pandera。不幸的是,它提供的功能非常有限,远远不是我们想要的。
下面是一个如何在您的案例中使用pandera的示例†:

import pandas as pd
import pandera as pa
from pandera.typing import DataFrame, Series, String

class MySchema(pa.DataFrameModel):
    a: Series[int]
    b: Series[float]
    c: Series[String]
    d: Series[float]    # US dollars

class OtherSchema(pa.DataFrameModel):
    year: Series[int] = pa.Field(ge=1900, le=2050)

def generate_data() -> DataFrame[MySchema]:
    df = pd.DataFrame({
        "a": [1, 2, 3],
        "b": [10.0, 20.0, 30.0],
        "c": ["A", "B", "C"],
        "d": [0.1, 0.2, 0.3],
    })

    # Runtime verification here, throws on schema mismatch
    strongly_typed_df = DataFrame[MySchema](df)
    return strongly_typed_df

def transform(input: DataFrame[MySchema]) -> DataFrame[OtherSchema]:
    # This demonstrates that you can use strongly
    # typed column names from the schema
    df = input.filter(items=[MySchema.a]).rename(
            columns={MySchema.a: OtherSchema.year}
    )

    return DataFrame[OtherSchema](df) # This will throw on range validation!

df1 = generate_data()
df2 = transform(df1)
transform(df2)   # mypy prints error here - incompatible type!

你可以看到mypy在最后一行产生了静态类型检查错误:

优点和局限性讨论

有了潘德拉我们就有了-
1.清晰易读的dataclass模式定义,并能够将其用作类型提示。
1.运行时模式验证。模式可以定义比类型更多的约束(参见下面示例中的yearpandera文档了解更多)。

  1. mypy对静态类型检查的实验性支持。
    我们仍然怀念的是-
    1.用于列级验证的完全静态类型检查。
    1.任何IDE对列名自动完成的支持。
    1.对于模式声明的内联语法,我们必须在使用它之前显式地将每个模式定义为单独的类。

更多示例

Pandera文档-https://pandera.readthedocs.io/en/stable/dataframe_models.html
类似问题-Type hints for a pandas DataFrame with mixed dtypes

其他打字项目

pandas-stubs是一个活跃的项目,为pandas公共API提供类型声明,比pandas本身包含的类型存根更丰富。但它不提供任何列级模式的工具。
有相当多的过时的库与此相关,pandas一般都是输入-dataenforcedata-science-typespython-type-stubs
pandera提供了两种不同的API,它们看起来同样强大-基于对象的API和基于类的API。我在这里演示了后者。

j91ykkif

j91ykkif3#

阿恩是对的,Python的类型提示没有任何原生的开箱即用的支持来指定Pandas DataFrame中的col类型。
您也许可以将注解与自定义类型一起使用

from typing import NamedTuple
import pandas as pd

class MyDataFrame(NamedTuple):
    a: int
    b: float
    c: str
    d: float  # US dollars as float

def generate_data(bunch, of, inputs) -> pd.DataFrame:
    """Massages the input to a nice and easy DataFrame.

    :return:
        DataFrame with columns a(int), b(float), c(string), d(us dollars as float)
    """
    # Your implementation here
    pass

这是一个可以采用的示例方法。它定义了一个名为MyDataFrame的自定义NamedTuple。当然,它并不是严格地对DataFrame进行类型提示,IDE和类型检查工具也不会强制执行它,但它向用户提供了一个关于输出DataFrame的预期结构体的提示。
您可以采用的另一种方法是使用自定义类型别名和docstring

from typing import Any, Dict
import pandas as pd

# Define a type alias for better documentation
DataFrameWithColumns = pd.DataFrame

def generate_data(bunch: Any, of: Any, inputs: Any) -> DataFrameWithColumns:
    """
    Massages the input to a nice and easy DataFrame.

    :param bunch: Description of the input parameter 'bunch'
    :param of: Description of the input parameter 'of'
    :param inputs: Description of the input parameter 'inputs'

    :return: DataFrame with columns:
        a (int): Description of column 'a'
        b (float): Description of column 'b'
        c (str): Description of column 'c'
        d (float): US dollars as float, description of column 'd'
    """
    # Your implementation here
    pass

在这里,您可以为pd.DataFrame定义一个自定义类型别名来表示expectec输出DataFrame,这对最终用户很有帮助

gudnpqoy

gudnpqoy4#

我不确定是否完全理解您的期望。难道df.info()不足以帮助用户吗?

>>> df.info()
<class '__main__.MyDataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 4 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   a       3 non-null      int64  
 1   b       3 non-null      float64
 2   c       3 non-null      object 
 3   d       3 non-null      float64
dtypes: float64(2), int64(1), object(1)
memory usage: 224.0+ bytes

如果没有,你可以子类化DataFrame并覆盖像info__repr__这样的方法。你可以在attrs字典中存储额外的信息并在这些方法中使用它。下面是一个例子:

class MyDataFrame(pd.DataFrame):
    
    def info(self):
        super().info()
        s = '\nMore information as footer:\n'
        s += self.attrs.get('more_info')
        print(s)

    def __repr__(self):
        s = 'More information as header:\n'
        s += f"{self.attrs.get('more_info')}\n\n"
        s += super().__repr__()
        return s
        
    @property
    def _constructor(self):
        return MyDataFrame

def generate_data(bunch, of, inputs) -> pd.DataFrame:
    df = MyDataFrame({'a': [0, 1, 2], 'b': [1.0, 1.1, 1.2],
                      'c': ['A', 'B', 'C'], 'd': [0.99, 2.49, 3.99]})
    df.attrs = {
        'more_info': 'Additional information here'
    }
    return df

df = generate_data('nothing', 'to', 'do')

使用方法:

>>> df
More information as header:  # <- HERE
Additional information here  # <- HERE

   a    b  c     d
0  0  1.0  A  0.99
1  1  1.1  B  2.49
2  2  1.2  C  3.99
>>> df.info()
<class '__main__.MyDataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 4 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   a       3 non-null      int64  
 1   b       3 non-null      float64
 2   c       3 non-null      object 
 3   d       3 non-null      float64
dtypes: float64(2), int64(1), object(1)
memory usage: 224.0+ bytes

More information as footer:  # <- HERE
Additional information here  # <- HERE
>>> df[['a', 'b']]
More information as header:
Additional information here

   a    b
0  0  1.0
1  1  1.1
2  2  1.2

我只是使用了一个简单的字符串,但你可以有一个更复杂的attrs结构和一个特殊的函数来显示这个dict(检查列是否存在,避免显示无用的信息)。

相关问题