PySpark读取文本数据转DataFrame问题求助(未找到对应方案)
嘿,看你提供的这段ICD疾病编码数据,前3个是短标识字段,后面俩是带空格的疾病名称,直接用默认CSV读取肯定会把字段内的空格当成分隔符,导致数据错乱。我给你几个实用的解决方案,都是实际项目里验证过的:
先贴下你的原始数据样例:
00001 A00 0 Cholera Cholera
00002 A000 1 Cholera due to Vibrio cholerae 01 biovar cholerae Cholera due to Vibrio cholerae 01 biovar cholerae
00003 A001 1 Cholera due to Vibrio cholerae 01 biovar eltor Cholera due to Vibrio cholerae 01 biovar eltor
00004 A009 1 Cholera unspecified Cholera unspecified
方案1:优先确认分隔符——大概率是制表符
很多医疗类数据会用制表符做分隔,避免字段内空格干扰。如果你的数据是这种情况,直接指定分隔符就行,Spark 2.0+之后不用第三方包,官方CSV读取器足够好用:
// Spark 2.0+ 官方写法 val data = spark.read .option("delimiter", "\t") // 把分隔符设为制表符 .option("header", "false") // 你的数据没有表头 .option("inferSchema", "true") // 让Spark自动推断字段类型,省得手动写Schema .csv("你的文件路径")
要是你还在用老版本Spark,把spark.read换成sqlContext.read.format("com.databricks.spark.csv")就行,其他参数一致。
方案2:固定长度字段用substring硬解析
如果前3个字段是固定长度(比如序号5位、编码3-4位、标识位1位),直接按位置截取最靠谱,完全不受空格干扰:
import org.apache.spark.sql.types._ // 先按纯文本读入每一行原始数据 val rawData = spark.read.text("你的文件路径") // 手动按位置切分并转换字段 val parsedData = rawData.select( substring(col("value"), 1, 5).alias("id"), // 第1-5位是序号 substring(col("value"), 7, 4).alias("code"), // 序号后有空格,从第7位开始取4位(兼容A00/A000两种长度) substring(col("value"), 12, 1).cast(IntegerType).alias("flag"), // 编码后有空格,第12位开始取1位转数字 // 用正则拆分剩余部分:跳过前13位(前3个字段+空格),拆成两个疾病名称 regexp_extract(col("value"), "^.{13}\\s+(.*?)\\s+(.*)$", 1).alias("disease_name1"), regexp_extract(col("value"), "^.{13}\\s+(.*?)\\s+(.*)$", 2).alias("disease_name2") )
方案3:正则表达式一键分割
要是不想算字段位置,用正则匹配更灵活,直接把整行按规则拆成数组:
val parsedData = rawData.select( // 正则规则:开头5位数字→空格→3-4位字母数字→空格→1位数字→空格→两段带空格的文本 split(col("value"), "^(\\d{5})\\s+(\\w{3,4})\\s+(\\d)\\s+(.*?)\\s+(.*)$", 0).alias("parts") ).select( col("parts").getItem(1).alias("id"), col("parts").getItem(2).alias("code"), col("parts").getItem(3).cast(IntegerType).alias("flag"), col("parts").getItem(4).alias("disease_name1"), col("parts").getItem(5).alias("disease_name2") )
小提醒
- 优先排查分隔符!如果是制表符,方案1最简单,效率也最高;
- 要是
inferSchema速度慢或者类型推断不准,就手动定义StructType,配合cast转换更稳妥; - Spark 2.0之后别再用
com.databricks.spark.csv了,官方的spark.read.csv功能更全,还不用额外导包。
内容的提问来源于stack exchange,提问作者Lizou

