我的表格中有[X,Y,强度]列,并希望从中生成图像。这些表可能很大,现在需要花费太多时间。因此,我正在寻找优化代码的方法。
代码使用如下所示的pandas数据帧:
import time
import cv2
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# Create demo version of the dataframes I use, which has similar characteristics as the real data
n = 27231221
df = pd.DataFrame({
"X": np.random.uniform(low=0.0, high=142.0, size=n),
"Y": np.random.uniform(low=0.0, high=142.0, size=n),
"intensity": np.random.randint(low=0, high=60, size=n)
})
df.head()
X Y intensity
0 63.643846 105.160795 11
1 123.693543 58.230852 55
2 2.289850 71.002206 42
3 132.666182 16.504936 7
4 99.317168 38.397257 56
代码本身如下:
# Resolution of the image, must stay like this
x_resolution=5e-2,
y_resolution=5e-2
start = time.time()
# Create bins with a certain resolution for the 2D histogram of the points
x_min = df["X"].min()
x_max = df["X"].max()
x_range = x_max - x_min
x_edges = np.linspace(start=x_min, stop=x_max,
num=np.ceil(x_range / x_resolution))
y_min = df["Y"].min()
y_max = df["Y"].max()
y_range = y_max - y_min
y_edges = np.linspace(start=y_min, stop=y_max,
num=np.ceil(y_range / y_resolution))
bins = (x_edges, y_edges)
# Timing
end = time.time()
print('Created bins in:', end - start)
start = end
# Create an histogram with the average bin intensity
im_n, _, _ = np.histogram2d(x=df["X"], y=df["Y"], bins=bins) # Number of points in each bin
# Timing
end = time.time()
print('Created hist, part A, in:', end - start)
start = end
im_n += 0.001 # Prevent division by zero is not possible
im_int, x, y = np.histogram2d(x=df["X"], y=df["Y"], bins=bins, weights=df["intensity"]) # Total intensity in each bin
im_mean = (im_int / im_n) # Average intensity in each bin
# Timing
end = time.time()
print('Created hist, part B, in:', end - start)
start = end
# From average intensity to normalized values suitable for displaying
# Note, there are outlier values which must not be take into consideration, hence the max_intensity
max_intensity = df["intensity"].quantile(0.98)
im_mean = np.clip(a=im_mean, a_min=0, a_max=max_intensity) / max_intensity
# Timing
end = time.time()
print('Created image in:', end - start)
start = end
# Kernel sizes for smoothing the image
close_kernel_size=3
# Connect pixels close to each other using a square in the image
kernel = np.ones((close_kernel_size, close_kernel_size))
im_mean = cv2.morphologyEx(im_mean, cv2.MORPH_CLOSE, kernel)
# Timing
end = time.time()
print('Smoothed image, part A, in:', end - start)
start = end
# Fill areas without high resolution pixels with lower resolution pixels
ellipse_kernel_size = 20
kernel = np.ones((ellipse_kernel_size, ellipse_kernel_size))
closing = cv2.morphologyEx(im_mean, cv2.MORPH_CLOSE, kernel)
idxs = im_mean == 0
im_mean[idxs] = closing[idxs]
# Timing
end = time.time()
print('Smoothed image, part B, in:', end - start)
start = end
# Show image
plt.figure(figsize=(3, 3))
plt.imshow(im_mean, cmap='gray')
输出看起来像这样:
Created bins in: 0.7478666305541992
Created hist, part A, in: 15.96267056465149
Created hist, part B, in: 16.237517833709717
Created image in: 0.426699161529541
Smoothed image, part A, in: 0.056333065032958984
Smoothed image, part B, in: 0.17376041412353516
<matplotlib.image.AxesImage at 0x7f6945f99ac8>
因此,显然,大多数改进可以通过改进直方图的创建来实现。但是我不知道这是否可行或如何实现。
除了调整上面的代码外,如果还有其他(更快)的方法可以将此类DataFrame转换为图像,我很想知道它们。
答案 0 :(得分:1)
嗯,所以只需将直方图代码修改为此:
im_n, _, _ = np.histogram2d(x=df["X"].values, y=df["Y"].values, bins=bins)
缩短了时间
Created hist, part A, in: 22.977999925613403
对此:
Created hist, part A, in: 6.108999967575073
因此两次通话的效率提高了近3倍
如果我使用to_numpy()
,也会得到类似的时间:
np.histogram2d(x=df["X"].to_numpy(), y=df["Y"].to_numpy(), bins=bins)
Created hist, part A, in: 6.01200008392334