Pyspark 更改带有子字符串的列
Pyspark alter column with substring
Pyspark n00b...如何用其自身的子字符串替换列?我正在尝试从字符串的开头和结尾删除 select 个字符。
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()
这非常接近但略有不同 。然后是这个
pyspark.sql.functions.substring(str, pos, len)
Substring starts at pos and is of length len when str is String type or returns the slice of byte array that starts at pos in byte and is of length len when str is Binary type
在您的代码中,
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()
尝试:
df.withColumn('COLUMN_NAME_fix', df['COLUMN_NAME'].substr(1, 10)).show()
其中 1 = 字符串中的起始位置和
10 = 从起始位置(含)开始要包括的字符数
接受的答案使用 udf
(用户定义的函数),它通常比本地 spark 代码慢(很多)。 Grant Shannon 的回答确实使用了本机 spark 代码,但正如 citynorman 在评论中指出的那样,对于可变字符串长度它是如何工作的并不是 100% 清楚。
使用原生 spark 代码(无 udf)和可变字符串长度回答
从pyspark中substr的文档可以看出,参数:startPos和length可以是int
或Column
类型(两者必须是同一类型) .所以我们只需要创建一个包含字符串长度的列并将其用作参数。
import pyspark.sql.functions as F
result = (
df
.withColumn('length', F.length('COLUMN_NAME'))
.withColumn('fixed_in_spark', F.col('COLUMN_NAME').substr(F.lit(2), F.col('length') - F.lit(2)))
)
# result:
+----------------+---------------+----+--------------+
| COLUMN_NAME|COLUMN_NAME_fix|size|fixed_in_spark|
+----------------+---------------+----+--------------+
| _string_| string| 8| string|
|_another string_| another string| 16|another string|
+----------------+---------------+----+--------------+
注:
- 我们使用长度 - 2,因为我们从第二个字符开始(并且需要直到倒数第二个字符的所有内容)。
- 我们需要使用
F.lit
,因为我们不能向 Column
对象添加(或减去)数字。我们需要先将该数字转换为 Column
.
如果目标是从列名中删除“_”,那么我会改用列表理解:
df.select(
[ col(c).alias(c.replace('_', '') ) for c in df.columns ]
)
Pyspark n00b...如何用其自身的子字符串替换列?我正在尝试从字符串的开头和结尾删除 select 个字符。
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()
这非常接近但略有不同
pyspark.sql.functions.substring(str, pos, len)
Substring starts at pos and is of length len when str is String type or returns the slice of byte array that starts at pos in byte and is of length len when str is Binary type
在您的代码中,
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()
尝试:
df.withColumn('COLUMN_NAME_fix', df['COLUMN_NAME'].substr(1, 10)).show()
其中 1 = 字符串中的起始位置和 10 = 从起始位置(含)开始要包括的字符数
接受的答案使用 udf
(用户定义的函数),它通常比本地 spark 代码慢(很多)。 Grant Shannon 的回答确实使用了本机 spark 代码,但正如 citynorman 在评论中指出的那样,对于可变字符串长度它是如何工作的并不是 100% 清楚。
使用原生 spark 代码(无 udf)和可变字符串长度回答
从pyspark中substr的文档可以看出,参数:startPos和length可以是int
或Column
类型(两者必须是同一类型) .所以我们只需要创建一个包含字符串长度的列并将其用作参数。
import pyspark.sql.functions as F
result = (
df
.withColumn('length', F.length('COLUMN_NAME'))
.withColumn('fixed_in_spark', F.col('COLUMN_NAME').substr(F.lit(2), F.col('length') - F.lit(2)))
)
# result:
+----------------+---------------+----+--------------+
| COLUMN_NAME|COLUMN_NAME_fix|size|fixed_in_spark|
+----------------+---------------+----+--------------+
| _string_| string| 8| string|
|_another string_| another string| 16|another string|
+----------------+---------------+----+--------------+
注:
- 我们使用长度 - 2,因为我们从第二个字符开始(并且需要直到倒数第二个字符的所有内容)。
- 我们需要使用
F.lit
,因为我们不能向Column
对象添加(或减去)数字。我们需要先将该数字转换为Column
.
如果目标是从列名中删除“_”,那么我会改用列表理解:
df.select(
[ col(c).alias(c.replace('_', '') ) for c in df.columns ]
)