gpt4 book ai didi

python - PySpark 中等效的 Scala 案例类是什么?

转载 作者:太空狗 更新时间:2023-10-29 17:42:43 26 4
gpt4 key购买 nike

您将如何在 PySpark 中使用和/或实现等效的案例类?

最佳答案

As mentioned通过 Alex Hall命名产品类型的真正等价物是 namedtuple

不同于Row,在the other answer中建议,它有许多有用的属性:

  • 具有明确的形状,可以可靠地用于结构模式匹配:

    >>> from collections import namedtuple
    >>>
    >>> FooBar = namedtuple("FooBar", ["foo", "bar"])
    >>> foobar = FooBar(42, -42)
    >>> foo, bar = foobar
    >>> foo
    42
    >>> bar
    -42

    对比 are not reliable when used with keyword arguments :

    >>> from pyspark.sql import Row
    >>>
    >>> foobar = Row(foo=42, bar=-42)
    >>> foo, bar = foobar
    >>> foo
    -42
    >>> bar
    42

    虽然如果用位置参数定义:

    >>> FooBar = Row("foo", "bar")
    >>> foobar = FooBar(42, -42)
    >>> foo, bar = foobar
    >>> foo
    42
    >>> bar
    -42

    顺序被保留。

  • 定义适当的类型

    >>> from functools import singledispatch
    >>>
    >>> FooBar = namedtuple("FooBar", ["foo", "bar"])
    >>> type(FooBar)
    <class 'type'>
    >>> isinstance(FooBar(42, -42), FooBar)
    True

    并且可以在需要类型处理的任何时候使用,尤其是对于单个:

    >>> Circle = namedtuple("Circle", ["x", "y", "r"])
    >>> Rectangle = namedtuple("Rectangle", ["x1", "y1", "x2", "y2"])
    >>>
    >>> @singledispatch
    ... def area(x):
    ... raise NotImplementedError
    ...
    ...
    >>> @area.register(Rectangle)
    ... def _(x):
    ... return abs(x.x1 - x.x2) * abs(x.y1 - x.y2)
    ...
    ...
    >>> @area.register(Circle)
    ... def _(x):
    ... return math.pi * x.r ** 2
    ...
    ...
    >>>
    >>> area(Rectangle(0, 0, 4, 4))
    16
    >>> >>> area(Circle(0, 0, 4))
    50.26548245743669

    multiple调度:

    >>> from multipledispatch import dispatch
    >>> from numbers import Rational
    >>>
    >>> @dispatch(Rectangle, Rational)
    ... def scale(x, y):
    ... return Rectangle(x.x1, x.y1, x.x2 * y, x.y2 * y)
    ...
    ...
    >>> @dispatch(Circle, Rational)
    ... def scale(x, y):
    ... return Circle(x.x, x.y, x.r * y)
    ...
    ...
    >>> scale(Rectangle(0, 0, 4, 4), 2)
    Rectangle(x1=0, y1=0, x2=8, y2=8)
    >>> scale(Circle(0, 0, 11), 2)
    Circle(x=0, y=0, r=22)

    结合第一个属性,可以在广泛的模式匹配场景中使用。 namedtuples 还支持标准继承和 type hints .

    不要:

    >>> FooBar = Row("foo", "bar")
    >>> type(FooBar)
    <class 'pyspark.sql.types.Row'>
    >>> isinstance(FooBar(42, -42), FooBar) # Expected failure
    Traceback (most recent call last):
    ...
    TypeError: isinstance() arg 2 must be a type or tuple of types
    >>> BarFoo = Row("bar", "foo")
    >>> isinstance(FooBar(42, -42), type(BarFoo))
    True
    >>> isinstance(BarFoo(42, -42), type(FooBar))
    True
  • 提供高度优化的表示。与 Row 对象不同,元组不使用 __dict__ 并在每个实例中携带字段名称。因此,初始化速度可以提高一个数量级:

    >>> FooBar = namedtuple("FooBar", ["foo", "bar"])
    >>> %timeit FooBar(42, -42)
    587 ns ± 5.28 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

    与不同的 Row 构造函数相比:

    >>> %timeit Row(foo=42, bar=-42)
    3.91 µs ± 7.67 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    >>> FooBar = Row("foo", "bar")
    >>> %timeit FooBar(42, -42)
    2 µs ± 25.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

    并且显着提高内存效率(处理大规模数据时非常重要的属性):

    >>> import sys
    >>> FooBar = namedtuple("FooBar", ["foo", "bar"])
    >>> sys.getsizeof(FooBar(42, -42))
    64

    与等效的 Row 相比>

    >>> sys.getsizeof(Row(foo=42, bar=-42))
    72

    最后,namedtuple 的属性访问速度提高了一个数量级:

    >>> FooBar = namedtuple("FooBar", ["foo", "bar"])
    >>> foobar = FooBar(42, -42)
    >>> %timeit foobar.foo
    102 ns ± 1.33 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

    Row 对象上的等效操作相比:

    >>> foobar = Row(foo=42, bar=-42)
    >>> %timeit foobar.foo
    2.58 µs ± 26.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  • 最后但同样重要的是 namedtuples 在 Spark SQL 中得到了正确的支持

    >>> Record = namedtuple("Record", ["id", "name", "value"])
    >>> spark.createDataFrame([Record(1, "foo", 42)])
    DataFrame[id: bigint, name: string, value: bigint]

总结:

很明显,Row 不能很好地替代 actual product type。 ,除非由 Spark API 强制执行,否则应避免使用。

还应该清楚的是,pyspark.sql.Row 并非旨在替代案例类,当您考虑这一点时,它直接等同于 org.apache.spark .sql.Row - 与实际产品相去甚远的类型,其行为类似于 Seq[Any](取决于子类,添加了名称)。 Python 和 Scala 实现都是作为外部代码和内部 Spark SQL 表示之间的有用但笨拙的接口(interface)而引入的。

另见:

  • 不提真棒就太可惜了MacroPyLi Haoyi 开发及其端口 ( MacroPy3 ),由 Alberto Berti 提供:

    >>> import macropy.console
    0=[]=====> MacroPy Enabled <=====[]=0
    >>> from macropy.case_classes import macros, case
    >>> @case
    ... class FooBar(foo, bar): pass
    ...
    >>> foobar = FooBar(42, -42)
    >>> foo, bar = foobar
    >>> foo
    42
    >>> bar
    -42

    它具有一组丰富的其他功能,包括但不限于高级模式匹配和简洁的 lambda 表达式语法。

  • python dataclasses (Python 3.7+)。

关于python - PySpark 中等效的 Scala 案例类是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37147450/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com