Pyspark用子串改变列

时间:2017-10-14 23:11:04

标签: pyspark pyspark-sql

Pyspark n00b ...如何用自身的子串替换列?我正在尝试从字符串的开头和结尾删除选定数量的字符。

from pyspark.sql.functions import substring
import pandas as pd
pdf = pd.DataFrame({'COLUMN_NAME':['_string_','_another string_']})
# this is what i'm looking for...
pdf['COLUMN_NAME_fix']=pdf['COLUMN_NAME'].str[1:-1] 

df = sqlContext.createDataFrame(pdf)
# following not working... COLUMN_NAME_fix is blank
df.withColumn('COLUMN_NAME_fix', substring('COLUMN_NAME', 1, -1)).show() 

这非常接近,但略有不同Spark Dataframe column with last character of other column。然后有这个 LEFT and RIGHT function in PySpark SQL

4 个答案:

答案 0 :(得分:7)

  

pyspark.sql.functions.substring(str,pos,len)

     

子串从pos开始,当str是String类型时长度为len,或者返回以字节开头的字节数组的片段,当str为二进制类型时,长度为len

在您的代码中,

df.withColumn('COLUMN_NAME_fix', substring('COLUMN_NAME', 1, -1))
1 is pos and -1 becomes len, length can't be -1 and so it returns null

试试这个,(使用固定语法)

from pyspark.sql.types import StringType
from pyspark.sql.functions import udf

udf1 = udf(lambda x:x[1:-1],StringType())
df.withColumn('COLUMN_NAME_fix',udf1('COLUMN_NAME')).show()

答案 1 :(得分:1)

可接受的答案使用udf(用户定义的函数),它通常比本机Spark代码慢很多。格兰特·香农(Grant Shannon)的答案的确使用了本地的火花代码,但正如citynorman的评论所指出的那样,对于可变长度的字符串,它的工作方式还不是100%清楚。

具有本机火花代码(无udf)和可变字符串长度的答案

从pyspark中substr的文档中,我们可以看到参数:startPos和length可以是intColumn类型(两者必须是同一类型)。因此,我们只需要创建一个包含字符串长度的列并将其用作参数即可。

import pyspark.sql.functions as sf

result = (
    df
    .withColumn('length', sf.length('COLUMN_NAME'))
    .withColumn('fixed_in_spark', col('COLUMN_NAME').substr(sf.lit(2), col('length') - sf.lit(2)))
)

# result:
+----------------+---------------+----+--------------+
|     COLUMN_NAME|COLUMN_NAME_fix|size|fixed_in_spark|
+----------------+---------------+----+--------------+
|        _string_|         string|   8|        string|
|_another string_| another string|  16|another string|
+----------------+---------------+----+--------------+

注意:

  • 我们使用长度-2,因为我们从第二个字符开始(并且需要所有字符直到第二个倒数)。
  • 我们需要使用sf.lit,因为我们无法向Column对象添加(或减去)数字。我们需要先将该数字转换为Column

答案 2 :(得分:0)

尝试:

df.withColumn('COLUMN_NAME_fix', df['COLUMN_NAME'].substr(1, 10)).show()

其中1 =字符串中的起始位置和      10 =从起始位置(包括)开始包含的字符数

答案 3 :(得分:0)

如果目标是从列名中删除“ _”,那么我将使用列表理解:

df.select(
    [ col(c).alias(c.replace('_', '') ) for c in df.columns ]
)