As I don't know your data, I give you a solution with my data (with x,y, z and a colum to test < 30). If I use your solution
import geopandas as gpd
import numpy as np
import pandas as pd
numpy_point_array = np.array([[202104.271187,90516.656257,170.520004272, 45],[202139.659561,90516.656257,170.740005493, 15],[202175.047935,90516.656257,170.809997559, 12],[202210.436309,90516.656257,170.75, 10],[202245.824683,90516.656257,170.13999939, 31]])
df = pd.DataFrame(numpy_point_array)
dfthresh = df.loc[df[3] < 30]
from shapely.geometry import Point
geometry = [Point(xyz) for xyz in zip(dfthresh[0], dfthresh[1], dfthresh[2])]
import geopandas as gpd
crs = {'init': 'epsg:27700'}
gdf = gpd.GeoDataFrame(dfthresh, crs=crs, geometry = geometry)
The name of the columns are
list(gdf)
[0, 1, 2, 3, 'geometry']
And a shapefile does not accept integers as column names -> Fiona error AttributeError: 'int' object has no attribute 'encode'
The solution ?, give a name to the fields when you create a DataFrame
# creation of a DataFrame with string column names
df = pd.DataFrame(numpy_point_array, columns=['x','y','z','test'])
df.head()
x y z test
0 202104.271187 90516.656257 170.520004 45.0
1 202139.659561 90516.656257 170.740005 15.0
2 202175.047935 90516.656257 170.809998 12.0
3 202210.436309 90516.656257 170.750000 10.0
4 202245.824683 90516.656257 170.139999 31.0
And you can simplify your script
# selection
df = df[df['test'] < 30]
df.head()
x y z test
1 202139.659561 90516.656257 170.740005 15.0
2 202175.047935 90516.656257 170.809998 12.0
3 202210.436309 90516.656257 170.750000 10.0
# convert to GeoDataFrame
# create a geometry column from the dataFrame x,y,z columns
df['geometry'] = df.apply(lambda row: Point(row.x,row.y,row.z),axis=1)
df = df.drop(['x', 'y', 'z'], axis=1)
# create the GeoDatFrame
gdf = gpd.GeoDatFrame(df, geometry = df.geometry)
# save the GeoDataFrame
gdf.to_file(driver = 'ESRI Shapefile', filename= "result.shp")
# or directly
gdf.to_file("result2.shp")