Python 通过在此数据帧的另一列上应用udf,在pyspark数据帧中创建一个新列

Python 通过在此数据帧的另一列上应用udf,在pyspark数据帧中创建一个新列,python,dataframe,filter,pyspark,count,Python,Dataframe,Filter,Pyspark,Count,我的数据是: +-----+-------+-----+-------+-----+-----+-----+----+----+----+ |carat| cut|color|clarity|depth|table|price| x| y| z| +-----+-------+-----+-------+-----+-----+-----+----+----+----+ | 0.23| Ideal| E| SI2| 61.5| 55.0| 326|3.95|3.

我的数据是:

+-----+-------+-----+-------+-----+-----+-----+----+----+----+
|carat|    cut|color|clarity|depth|table|price|   x|   y|   z|
+-----+-------+-----+-------+-----+-----+-----+----+----+----+
| 0.23|  Ideal|    E|    SI2| 61.5| 55.0|  326|3.95|3.98|2.43|
| 0.21|Premium|    E|    SI1| 59.8| 61.0|  326|3.89|3.84|2.31|
| 0.23|   Good|    E|    VS1| 56.9| 65.0|  327|4.05|4.07|2.31|
| 0.29|Premium|    I|    VS2| 62.4| 58.0|  334| 4.2|4.23|2.63|
| 0.31|   Good|    J|    SI2| 63.3| 58.0|  335|4.34|4.35|2.75|
我创建了一个函数,它读取列carat并返回每个值的间隔。我需要用这个间隔组成一个新的列

结果应该是:

carat carat_bin
0.23    (0.1)
1.5      (1,2)
到目前为止,我的代码是:

def carat_bin(size) :
  if ((df['size'] >0) & (df['size'] <= 1)):
    return '[0,1)'
  if ((df['size'] >1) & (df['size'] <= 2)):
    return '[1,2)'
  if ((df['size'] >2) & (df['size'] <= 3)):
    return '[2,3)'
  if ((df['size'] >3) & (df['size'] <= 4)):
    return '[3,4)'
  if ((df['size'] >4) & (df['size'] <= 5)):
    return '[4,5)'
  elif df['size'] :
    return '[5, 6)'
  spark.udf.register('carat_bin', carat_bin)
  tst = diamonds.withColumn("carat_bin", carat_bin(diamonds['carat']))
我缺少什么?

修改您的解决方案 您的问题是,您的udf显式地查找全局定义的
df
,并且没有以任何方式使用它的
size
参数

试试这个:

from pyspark.sql import functions as F
from pyspark.sql.types import StringType

@F.udf(StringType())
def bin_carat(s):
    if 0 < s <= 1:
        return '[0,1)'
    if 1 < s <= 2:
        return '[1,2)'
    if 2 < s <= 3:
        return '[2,3)'
    if 3 < s <= 4:
        return '[3,4)'
    if 4 < s <= 5:
        return '[4,5)'
    elif s:
        return '[5, 6)'

diamonds.withColumn("carat_bin", bin_carat(diamonds['carat'])).show()
对于您的数据帧,正如预期的那样。 使用
spark.udf.register('carat_-bin',carat_-bin)
时似乎有一个根本性的区别,这总是导致错误

使用自定义项 如果您使用pyspark 2.3及更高版本,有一种更简单的方法可以使用UDF实现这一点。请看一下以下内容:

from pyspark.sql.functions import PandasUDFType
import pandas as pd
from pyspark.sql.functions import pandas_udf

@pandas_udf(StringType(), PandasUDFType.SCALAR)
def cut_to_str(s):
    return pd.cut(s, bins=[0,1,2,3,4,5], labels=['[0,1)', '[1,2)', '[2,3)', '[3,4)', '[4,5)']).astype(str)
以与先前定义的自定义项相同的方式使用此选项:

diamonds.withColumn("carat_bin", cut_to_str(diamonds['carat'])).show()

它将产生与上面所示完全相同的数据帧。

为什么不使用padas pd.qcut(菱形[“大小”],q=5,精度=0,标签=False)@TobiasBruckert中的内置函数,因为分位数取决于您所交的实际数据,但是OP想在演员阵容中固定limitsTrue,pd.cut是否能胜任这项工作。是的,在您链接的问题中,它确实起作用,因为它在这个特殊情况下起作用。@user1997567:我在回答中提到了这一点。实际上,我不知道udf和
spark.udf.register发生了什么不同
from pyspark.sql.functions import PandasUDFType
import pandas as pd
from pyspark.sql.functions import pandas_udf

@pandas_udf(StringType(), PandasUDFType.SCALAR)
def cut_to_str(s):
    return pd.cut(s, bins=[0,1,2,3,4,5], labels=['[0,1)', '[1,2)', '[2,3)', '[3,4)', '[4,5)']).astype(str)
diamonds.withColumn("carat_bin", cut_to_str(diamonds['carat'])).show()