Python读取xyz转shapefile报must be real number not str错
问题原因
报错must be real number, not str的直接原因是构造shapely的Point对象时传入了字符串类型值,不符合坐标必须为数值的要求,根因是代码的文件读取逻辑存在几个明确问题:
- 分隔符配置不匹配:你提供的xyz样例使用空格作为列分隔符,但代码中读取xyz/asc时的分隔符规则
sep=r'\,|\t'仅匹配逗号和制表符,完全没有覆盖空格场景,pandas无法将每行正确拆分为x、y、z三个独立列,要么整行内容作为字符串存入第一列,要么拆分后列值保留字符串类型,传入Point时直接触发类型错误。 - 硬编码跳行逻辑错误:你给出的xyz文件全为数值数据,不存在前置表头/说明行,代码中写死的
skiprows=2会直接跳过前两行有效坐标,属于冗余bug,虽不触发本次报错,但会造成数据丢失。 - 额外兼容隐患:代码用
os.path.basename(xyz_path)[:-4]提取输出文件名,硬编码切片长度仅适配3位长度的扩展名,遇到.text这类4位扩展名的文件会把文件名切坏;读取文件时未显式指定列类型,遇到异常值时pandas可能自动将列识别为字符串类型,触发同类报错。
修复方法
- 将分隔符统一改为
r'\s+',可匹配任意数量的空格、制表符、连续空白,覆盖所有常见的坐标文本文件分隔场景。 - 移除硬编码的
skiprows=2,如果部分文件确实带2行前置说明,单独加判断逻辑,不要全局生效。 - 读取文件时显式指定x/y/z三列为float类型,避免pandas自动识别类型出错。
- 用
os.path.splitext替换硬编码切片的文件名提取逻辑,兼容任意长度的扩展名。 - 读取后过滤空值行,避免缺失值传入Point构造函数。
修复后的核心代码段如下:
try: xyz_path = self.jobDict['xyz_key'][0] print(f'{datetime.now()} get_object (start)') input_file = self.s3_client.get_object(Bucket=self.jobDict['bucket'], Key=xyz_path) print(f'{datetime.now()} get_object (end) : {xyz_path}') file_extension = os.path.splitext(xyz_path)[-1].lower() # 安全提取无扩展名的文件名 output_file = os.path.splitext(os.path.basename(xyz_path))[0] file_content = io.BytesIO(input_file['Body'].read()) if file_extension in ("xyz", "asc"): df = pd.read_table( file_content, sep=r'\s+', engine='python', names=['x', 'y', 'z'], dtype={'x': float, 'y': float, 'z': float} ) elif file_extension in ("txt", "text", "csv"): df = pd.read_csv( file_content, sep=r'\s+', names=['x', 'y', 'z'], dtype={'x': float, 'y': float, 'z': float} ) # 过滤含空值的无效数据行 df = df.dropna(subset=['x', 'y', 'z']) gdf = gpd.GeoDataFrame( df, geometry=df.apply(lambda row: Point(row.x, row.y, row.z), axis=1), # 根据数据实际坐标系指定crs,避免后续空间处理出错 crs="EPSG:326XX" ) gdf.to_file(f"{output_file}.shp") shapefile = f"{output_file}.shp" print("Shapefile Created!")
注:如果业务场景中确实存在带2行表头的xyz/asc文件,不要直接写死
skiprows=2,可以先读取文件前N行判断内容是否为数值,动态决定跳过行数,避免误删有效数据。
内容的提问来源于stack exchange,提问作者userhelp
相关产品推荐
相关产品推荐

