slightly improved performance
Browse files- handcrafted_solution.py +100 -117
- test_solution.ipynb +29 -17
handcrafted_solution.py
CHANGED
@@ -28,7 +28,7 @@ def empty_solution():
|
|
28 |
|
29 |
def undesired_objects(image):
|
30 |
image = image.astype('uint8')
|
31 |
-
nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity=
|
32 |
sizes = stats[:, -1]
|
33 |
max_label = 1
|
34 |
max_size = sizes[1]
|
@@ -73,8 +73,8 @@ def get_vertices(image_gestalt, *, color_range=4., dialations=3, erosions=1, ker
|
|
73 |
eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_DILATE, kernel, iterations=dialations)
|
74 |
eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_ERODE, kernel, iterations=erosions)
|
75 |
|
76 |
-
*_, apex_centroids = cv2.connectedComponentsWithStats(apex_mask, connectivity=
|
77 |
-
*_, other_centroids = cv2.connectedComponentsWithStats(eave_end_point_mask, connectivity=
|
78 |
|
79 |
return apex_centroids[1:], other_centroids[1:], apex_mask, eave_end_point_mask
|
80 |
|
@@ -96,7 +96,7 @@ def infer_vertices(image_gestalt, *, color_range=4.):
|
|
96 |
intersection_mask = cv2.bitwise_and(ridge_mask, rake_mask)
|
97 |
intersection_mask = cv2.morphologyEx(intersection_mask, cv2.MORPH_DILATE, np.ones((11, 11)), iterations=3)
|
98 |
|
99 |
-
*_, inferred_centroids = cv2.connectedComponentsWithStats(intersection_mask, connectivity=
|
100 |
|
101 |
return inferred_centroids[1:], intersection_mask
|
102 |
|
@@ -144,15 +144,17 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, color_range=4., poi
|
|
144 |
# missed_vertices = get_missed_vertices(vertices, inferred_vertices, **kwargs)
|
145 |
# vertices = np.concatenate([vertices, missed_vertices])
|
146 |
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
|
|
|
|
153 |
|
154 |
for edge_class in ['eave', 'ridge', 'rake', 'valley', 'flashing', 'step_flashing']:
|
155 |
-
if len(vertices) < 2:
|
156 |
break
|
157 |
edge_color = np.array(gestalt_color_mapping[edge_class])
|
158 |
|
@@ -162,117 +164,100 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, color_range=4., poi
|
|
162 |
mask = cv2.morphologyEx(mask,
|
163 |
cv2.MORPH_DILATE, np.ones((3, 3)), iterations=1)
|
164 |
|
165 |
-
if np.any(mask):
|
|
|
166 |
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
|
179 |
-
|
180 |
|
181 |
-
|
182 |
-
|
183 |
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
|
193 |
-
|
194 |
|
195 |
-
|
196 |
-
|
197 |
|
198 |
-
|
199 |
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
# where both ends are in range
|
214 |
-
begin_in_range_mask = np.logical_and(begin_in_range_mask, in_range_connected_mask)
|
215 |
-
end_in_range_mask = np.logical_and(end_in_range_mask, in_range_connected_mask)
|
216 |
-
|
217 |
-
begin_candidates = np.array(np.where(begin_in_range_mask))
|
218 |
-
end_candidates = np.array(np.where(end_in_range_mask))
|
219 |
-
|
220 |
-
# sort the candidates by line index; required for the seamlessnes np.split
|
221 |
-
sorted_begin_indices = np.argsort(begin_candidates[1])
|
222 |
-
sorted_end_indices = np.argsort(end_candidates[1])
|
223 |
-
begin_candidates = begin_candidates[:, sorted_begin_indices]
|
224 |
-
end_candidates = end_candidates[:, sorted_end_indices]
|
225 |
-
|
226 |
-
# create all possible connections between begin and end candidates that correspond to a line
|
227 |
-
grouped_begins = np.split(begin_candidates[0], np.unique(begin_candidates[1], return_index=True)[1][1:])
|
228 |
-
grouped_ends = np.split(end_candidates[0], np.unique(end_candidates[1], return_index=True)[1][1:])
|
229 |
-
line_indices = np.unique(begin_candidates[1])
|
230 |
-
|
231 |
-
# create all possible connections between begin and end candidates that correspond to a line
|
232 |
-
begin_vertex_list = []
|
233 |
-
end_vertex_list = []
|
234 |
-
line_idx_list = []
|
235 |
-
for begin_vertex, end_vertex, line_idx in zip(grouped_begins, grouped_ends, line_indices):
|
236 |
-
begin_vertex, end_vertex = np.meshgrid(begin_vertex, end_vertex)
|
237 |
-
begin_vertex_list.extend(begin_vertex.flatten())
|
238 |
-
end_vertex_list.extend(end_vertex.flatten())
|
239 |
-
line_idx_list.extend([line_idx] * len(begin_vertex.flatten()))
|
240 |
-
|
241 |
-
line_idx_list = np.array(line_idx_list)
|
242 |
-
all_connections = np.array([begin_vertex_list, end_vertex_list])
|
243 |
-
|
244 |
-
# decrease the number of possible connections to reduce number of calculations
|
245 |
-
possible_connections = np.unique(all_connections, axis=1)
|
246 |
-
possible_connections = np.sort(possible_connections, axis=0)
|
247 |
-
possible_connections = np.unique(possible_connections, axis=1)
|
248 |
-
possible_connections = possible_connections[:, possible_connections[0, :] != possible_connections[1, :]]
|
249 |
-
|
250 |
-
if possible_connections.shape[1] < 1:
|
251 |
-
continue
|
252 |
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
276 |
|
277 |
vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
|
278 |
# vertices += [{"xy": v, "type": "apex"} for v in missed_vertices]
|
@@ -282,10 +267,8 @@ def get_vertices_and_edges_from_segmentation(gest_seg_np, *, color_range=4., poi
|
|
282 |
|
283 |
def get_uv_depth(vertices, depth):
|
284 |
'''Get the depth of the vertices from the depth image'''
|
285 |
-
|
286 |
-
for v in vertices
|
287 |
-
uv.append(v['xy'])
|
288 |
-
uv = np.array(uv)
|
289 |
uv_int = uv.astype(np.int32)
|
290 |
H, W = depth.shape[:2]
|
291 |
uv_int[:, 0] = np.clip(uv_int[:, 0], 0, W - 1)
|
@@ -387,7 +370,7 @@ def predict(entry, visualize=False, scale_estimation_coefficient=2.5, **kwargs)
|
|
387 |
gest_seg = gest.resize(depth.size)
|
388 |
gest_seg_np = np.array(gest_seg).astype(np.uint8)
|
389 |
# Metric3D
|
390 |
-
depth_np = np.array(depth) / scale_estimation_coefficient
|
391 |
vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, **kwargs)
|
392 |
if (len(vertices) < 2) or (len(connections) < 1):
|
393 |
print(f'Not enough vertices or connections in image {i}')
|
|
|
28 |
|
29 |
def undesired_objects(image):
|
30 |
image = image.astype('uint8')
|
31 |
+
nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(image, connectivity=4)
|
32 |
sizes = stats[:, -1]
|
33 |
max_label = 1
|
34 |
max_size = sizes[1]
|
|
|
73 |
eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_DILATE, kernel, iterations=dialations)
|
74 |
eave_end_point_mask = cv2.morphologyEx(eave_end_point_mask, cv2.MORPH_ERODE, kernel, iterations=erosions)
|
75 |
|
76 |
+
*_, apex_centroids = cv2.connectedComponentsWithStats(apex_mask, connectivity=4, stats=cv2.CV_32S)
|
77 |
+
*_, other_centroids = cv2.connectedComponentsWithStats(eave_end_point_mask, connectivity=4, stats=cv2.CV_32S)
|
78 |
|
79 |
return apex_centroids[1:], other_centroids[1:], apex_mask, eave_end_point_mask
|
80 |
|
|
|
96 |
intersection_mask = cv2.bitwise_and(ridge_mask, rake_mask)
|
97 |
intersection_mask = cv2.morphologyEx(intersection_mask, cv2.MORPH_DILATE, np.ones((11, 11)), iterations=3)
|
98 |
|
99 |
+
*_, inferred_centroids = cv2.connectedComponentsWithStats(intersection_mask, connectivity=4, stats=cv2.CV_32S)
|
100 |
|
101 |
return inferred_centroids[1:], intersection_mask
|
102 |
|
|
|
144 |
# missed_vertices = get_missed_vertices(vertices, inferred_vertices, **kwargs)
|
145 |
# vertices = np.concatenate([vertices, missed_vertices])
|
146 |
|
147 |
+
vertices = KDTree(vertices)
|
148 |
+
|
149 |
+
# scale = 1
|
150 |
+
# vertex_size = np.zeros(vertices.shape[0])
|
151 |
+
# for i, coords in enumerate(vertices):
|
152 |
+
# # coords = np.round(coords).astype(np.uint32)
|
153 |
+
# radius = point_radius # np.clip(int(max_depth//2 + depth_np[coords[1], coords[0]]), 10, 30)#int(np.clip(max_depth - depth_np[coords[1], coords[0]], 10, 20))
|
154 |
+
# vertex_size[i] = (scale * radius) ** 2 # because we are using squared distances
|
155 |
|
156 |
for edge_class in ['eave', 'ridge', 'rake', 'valley', 'flashing', 'step_flashing']:
|
157 |
+
if len(vertices.data) < 2:
|
158 |
break
|
159 |
edge_color = np.array(gestalt_color_mapping[edge_class])
|
160 |
|
|
|
164 |
mask = cv2.morphologyEx(mask,
|
165 |
cv2.MORPH_DILATE, np.ones((3, 3)), iterations=1)
|
166 |
|
167 |
+
if not np.any(mask):
|
168 |
+
continue
|
169 |
|
170 |
+
rho = 1 # distance resolution in pixels of the Hough grid
|
171 |
+
theta = np.pi / 180 # angular resolution in radians of the Hough grid
|
172 |
+
threshold = 20 # minimum number of votes (intersections in Hough grid cell)
|
173 |
+
min_line_length = 60 # minimum number of pixels making up a line
|
174 |
+
max_line_gap = 40 # maximum gap in pixels between connectable line segments
|
175 |
|
176 |
+
# Run Hough on edge detected image
|
177 |
+
# Output "lines" is an array containing endpoints of detected line segments
|
178 |
+
cv2.GaussianBlur(mask, (11, 11), 0, mask)
|
179 |
+
lines = cv2.HoughLinesP(mask, rho, theta, threshold, np.array([]),
|
180 |
+
min_line_length, max_line_gap)
|
181 |
|
182 |
+
edges = []
|
183 |
|
184 |
+
if lines is None:
|
185 |
+
continue
|
186 |
|
187 |
+
line_directions = np.zeros((len(lines), 2))
|
188 |
+
for line_idx, line in enumerate(lines):
|
189 |
+
for x1, y1, x2, y2 in line:
|
190 |
+
if x1 < x2:
|
191 |
+
x1, y1, x2, y2 = x2, y2, x1, y1
|
192 |
+
direction = (np.array([x2 - x1, y2 - y1]))
|
193 |
+
direction = direction / np.linalg.norm(direction)
|
194 |
+
line_directions[line_idx] = direction
|
195 |
|
196 |
+
direction = extend * direction
|
197 |
|
198 |
+
x1, y1 = (-direction + (x1, y1)).astype(np.int32)
|
199 |
+
x2, y2 = (+ direction + (x2, y2)).astype(np.int32)
|
200 |
|
201 |
+
edges.append((x1, y1, x2, y2))
|
202 |
|
203 |
+
edges = np.array(edges).astype(np.float64)
|
204 |
+
if len(edges) < 1:
|
205 |
+
continue
|
206 |
+
# calculate the distances between the vertices and the edge ends
|
207 |
+
|
208 |
+
begin_edges = KDTree(edges[:, :2])
|
209 |
+
end_edges = KDTree(edges[:, 2:])
|
210 |
+
|
211 |
+
begin_indices = begin_edges.query_ball_tree(vertices, point_radius)
|
212 |
+
end_indices = end_edges.query_ball_tree(vertices, point_radius)
|
213 |
+
|
214 |
+
line_indices = np.where(np.array([len(i) and len(j) for i, j in zip(begin_indices, end_indices)]))[0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
|
216 |
+
# create all possible connections between begin and end candidates that correspond to a line
|
217 |
+
begin_vertex_list = []
|
218 |
+
end_vertex_list = []
|
219 |
+
line_idx_list = []
|
220 |
+
for line_idx in line_indices:
|
221 |
+
begin_vertex, end_vertex = begin_indices[line_idx], end_indices[line_idx]
|
222 |
+
begin_vertex, end_vertex = np.meshgrid(begin_vertex, end_vertex)
|
223 |
+
begin_vertex_list.extend(begin_vertex.flatten())
|
224 |
+
end_vertex_list.extend(end_vertex.flatten())
|
225 |
+
|
226 |
+
line_idx_list.extend([line_idx] * len(begin_vertex.flatten()))
|
227 |
+
|
228 |
+
line_idx_list = np.array(line_idx_list)
|
229 |
+
all_connections = np.array([begin_vertex_list, end_vertex_list])
|
230 |
+
|
231 |
+
# decrease the number of possible connections to reduce number of calculations
|
232 |
+
possible_connections = np.unique(all_connections, axis=1)
|
233 |
+
possible_connections = np.sort(possible_connections, axis=0)
|
234 |
+
possible_connections = np.unique(possible_connections, axis=1)
|
235 |
+
possible_connections = possible_connections[:, possible_connections[0, :] != possible_connections[1, :]]
|
236 |
+
|
237 |
+
if possible_connections.shape[1] < 1:
|
238 |
+
continue
|
239 |
+
|
240 |
+
# precalculate the possible direction vectors
|
241 |
+
possible_direction_vectors = vertices.data[possible_connections[0]] - vertices.data[possible_connections[1]]
|
242 |
+
possible_direction_vectors = possible_direction_vectors / np.linalg.norm(possible_direction_vectors, axis=1)[:, np.newaxis]
|
243 |
+
|
244 |
+
owned_lines_per_possible_connections = [list() for i in range(possible_connections.shape[1])]
|
245 |
+
|
246 |
+
# assign lines to possible connections
|
247 |
+
for line_idx, i,j in zip(line_idx_list, begin_vertex_list, end_vertex_list):
|
248 |
+
if i == j:
|
249 |
+
continue
|
250 |
+
i, j = min(i, j), max(i, j)
|
251 |
+
for connection_idx, connection in enumerate(possible_connections.T):
|
252 |
+
if np.all((i, j) == connection):
|
253 |
+
owned_lines_per_possible_connections[connection_idx].append(line_idx)
|
254 |
+
break
|
255 |
+
|
256 |
+
# check if the lines are in the same direction as the possible connection
|
257 |
+
for fitted_line_idx, owned_lines_per_possible_connection in enumerate(owned_lines_per_possible_connections):
|
258 |
+
line_deviations = np.abs(np.dot(line_directions[owned_lines_per_possible_connection], possible_direction_vectors[fitted_line_idx]))
|
259 |
+
if np.any(line_deviations > deviation_threshold):
|
260 |
+
connections.append(possible_connections[:, fitted_line_idx])
|
261 |
|
262 |
vertices = [{"xy": v, "type": "apex"} for v in apex_centroids]
|
263 |
# vertices += [{"xy": v, "type": "apex"} for v in missed_vertices]
|
|
|
267 |
|
268 |
def get_uv_depth(vertices, depth):
|
269 |
'''Get the depth of the vertices from the depth image'''
|
270 |
+
|
271 |
+
uv = np.array([v['xy'] for v in vertices])
|
|
|
|
|
272 |
uv_int = uv.astype(np.int32)
|
273 |
H, W = depth.shape[:2]
|
274 |
uv_int[:, 0] = np.clip(uv_int[:, 0], 0, W - 1)
|
|
|
370 |
gest_seg = gest.resize(depth.size)
|
371 |
gest_seg_np = np.array(gest_seg).astype(np.uint8)
|
372 |
# Metric3D
|
373 |
+
depth_np = np.array(depth) / scale_estimation_coefficient
|
374 |
vertices, connections = get_vertices_and_edges_from_segmentation(gest_seg_np, **kwargs)
|
375 |
if (len(vertices) < 2) or (len(connections) < 1):
|
376 |
print(f'Not enough vertices or connections in image {i}')
|
test_solution.ipynb
CHANGED
@@ -6,8 +6,8 @@
|
|
6 |
"metadata": {
|
7 |
"collapsed": true,
|
8 |
"ExecuteTime": {
|
9 |
-
"end_time": "2024-05-
|
10 |
-
"start_time": "2024-05-
|
11 |
}
|
12 |
},
|
13 |
"source": [
|
@@ -44,8 +44,8 @@
|
|
44 |
{
|
45 |
"metadata": {
|
46 |
"ExecuteTime": {
|
47 |
-
"end_time": "2024-05-
|
48 |
-
"start_time": "2024-05-
|
49 |
}
|
50 |
},
|
51 |
"cell_type": "code",
|
@@ -64,8 +64,8 @@
|
|
64 |
{
|
65 |
"metadata": {
|
66 |
"ExecuteTime": {
|
67 |
-
"end_time": "2024-05-
|
68 |
-
"start_time": "2024-05-
|
69 |
}
|
70 |
},
|
71 |
"cell_type": "code",
|
@@ -83,8 +83,8 @@
|
|
83 |
{
|
84 |
"metadata": {
|
85 |
"ExecuteTime": {
|
86 |
-
"end_time": "2024-05-
|
87 |
-
"start_time": "2024-05-
|
88 |
}
|
89 |
},
|
90 |
"cell_type": "code",
|
@@ -93,10 +93,16 @@
|
|
93 |
"\n",
|
94 |
"solution = []\n",
|
95 |
"from concurrent.futures import ProcessPoolExecutor\n",
|
96 |
-
"with ProcessPoolExecutor(max_workers=
|
97 |
" results = []\n",
|
98 |
" for i, sample in enumerate(tqdm(dataset)):\n",
|
99 |
-
" results.append(pool.submit(predict, sample
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
"\n",
|
101 |
" for i, result in enumerate(tqdm(results)):\n",
|
102 |
" key, pred_vertices, pred_edges = result.result()\n",
|
@@ -116,18 +122,18 @@
|
|
116 |
"name": "stderr",
|
117 |
"output_type": "stream",
|
118 |
"text": [
|
119 |
-
"346it [00:11,
|
120 |
-
"100%|ββββββββββ| 346/346 [01:
|
121 |
]
|
122 |
}
|
123 |
],
|
124 |
-
"execution_count":
|
125 |
},
|
126 |
{
|
127 |
"metadata": {
|
128 |
"ExecuteTime": {
|
129 |
-
"end_time": "2024-05-
|
130 |
-
"start_time": "2024-05-
|
131 |
}
|
132 |
},
|
133 |
"cell_type": "code",
|
@@ -160,12 +166,18 @@
|
|
160 |
"DescribeResult(nobs=173, minmax=(1.3699674819647794, 3.507189015362208), mean=2.159528576281002, variance=0.19517651860816773, skewness=0.5493231777924736, kurtosis=-0.14096706768318912)"
|
161 |
]
|
162 |
},
|
163 |
-
"execution_count":
|
164 |
"metadata": {},
|
165 |
"output_type": "execute_result"
|
166 |
}
|
167 |
],
|
168 |
-
"execution_count":
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
},
|
170 |
{
|
171 |
"metadata": {
|
|
|
6 |
"metadata": {
|
7 |
"collapsed": true,
|
8 |
"ExecuteTime": {
|
9 |
+
"end_time": "2024-05-30T19:40:29.917386Z",
|
10 |
+
"start_time": "2024-05-30T19:40:26.483885Z"
|
11 |
}
|
12 |
},
|
13 |
"source": [
|
|
|
44 |
{
|
45 |
"metadata": {
|
46 |
"ExecuteTime": {
|
47 |
+
"end_time": "2024-05-30T19:40:29.922957Z",
|
48 |
+
"start_time": "2024-05-30T19:40:29.918391Z"
|
49 |
}
|
50 |
},
|
51 |
"cell_type": "code",
|
|
|
64 |
{
|
65 |
"metadata": {
|
66 |
"ExecuteTime": {
|
67 |
+
"end_time": "2024-05-30T19:40:29.927010Z",
|
68 |
+
"start_time": "2024-05-30T19:40:29.923961Z"
|
69 |
}
|
70 |
},
|
71 |
"cell_type": "code",
|
|
|
83 |
{
|
84 |
"metadata": {
|
85 |
"ExecuteTime": {
|
86 |
+
"end_time": "2024-05-30T19:46:53.539149Z",
|
87 |
+
"start_time": "2024-05-30T19:45:17.379935Z"
|
88 |
}
|
89 |
},
|
90 |
"cell_type": "code",
|
|
|
93 |
"\n",
|
94 |
"solution = []\n",
|
95 |
"from concurrent.futures import ProcessPoolExecutor\n",
|
96 |
+
"with ProcessPoolExecutor(max_workers=10) as pool:\n",
|
97 |
" results = []\n",
|
98 |
" for i, sample in enumerate(tqdm(dataset)):\n",
|
99 |
+
" results.append(pool.submit(predict, sample,\n",
|
100 |
+
" point_radius=25, \n",
|
101 |
+
" max_angle=15, \n",
|
102 |
+
" extend=30, \n",
|
103 |
+
" merge_th=3.0, \n",
|
104 |
+
" min_missing_distance=10000.0, \n",
|
105 |
+
" scale_estimation_coefficient=4))\n",
|
106 |
"\n",
|
107 |
" for i, result in enumerate(tqdm(results)):\n",
|
108 |
" key, pred_vertices, pred_edges = result.result()\n",
|
|
|
122 |
"name": "stderr",
|
123 |
"output_type": "stream",
|
124 |
"text": [
|
125 |
+
"346it [00:11, 29.44it/s] \n",
|
126 |
+
"100%|ββββββββββ| 346/346 [01:23<00:00, 4.15it/s]\n"
|
127 |
]
|
128 |
}
|
129 |
],
|
130 |
+
"execution_count": 7
|
131 |
},
|
132 |
{
|
133 |
"metadata": {
|
134 |
"ExecuteTime": {
|
135 |
+
"end_time": "2024-05-30T19:42:15.830560Z",
|
136 |
+
"start_time": "2024-05-30T19:42:15.185713Z"
|
137 |
}
|
138 |
},
|
139 |
"cell_type": "code",
|
|
|
166 |
"DescribeResult(nobs=173, minmax=(1.3699674819647794, 3.507189015362208), mean=2.159528576281002, variance=0.19517651860816773, skewness=0.5493231777924736, kurtosis=-0.14096706768318912)"
|
167 |
]
|
168 |
},
|
169 |
+
"execution_count": 5,
|
170 |
"metadata": {},
|
171 |
"output_type": "execute_result"
|
172 |
}
|
173 |
],
|
174 |
+
"execution_count": 5
|
175 |
+
},
|
176 |
+
{
|
177 |
+
"metadata": {},
|
178 |
+
"cell_type": "markdown",
|
179 |
+
"source": "best mean=2.159528576281002",
|
180 |
+
"id": "1d3cde94dcfc4c56"
|
181 |
},
|
182 |
{
|
183 |
"metadata": {
|