首页 > 解决方案 > 如何从 30 个 csv 文件制作直方图以绘制直方图,然后使用高斯函数和标准差绘制直方图?

问题描述

我想从 30 个 csv 文件中制作一个直方图,然后拟合一个高斯函数来查看我的数据是否是最优的。之后,我需要找到这些峰的平均值和标准差。文件数据太大,我不知道我是否提取了单个列并将它们的值范围正确地组织到了 bin 的数量中。

我知道这有点长而且问题太多,请尽可能多地回答,非常感谢!

> 这是数据的链接

到目前为止我已经完成了以下(实际上并不多,因为我是数据可视化的初学者。)首先,我导入包,savgol_filter使bin透明,看起来更好。

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.signal import savgol_filter

然后我转换尺寸并设置限制。

def cm2inch(value):
    return value/2.54

width = 9
height = 6.75

sliceMin, sliceMax = 300, 1002

接下来,我通过迭代 30 次加载所有数据 jupyter notebook,其中我设置了两个数组“times”和“voltages”来存储值。

times, voltages = [], []
for i in range(30):
    time, ch1 = np.loadtxt(f"{i+1}.txt", delimiter=',', skiprows=5,unpack=True)
    times.append(time)
    voltages.append(ch1)    
t = (np.array(times[0]) * 1e5)[sliceMin:sliceMax]
voltages = (np.array(voltages))[:, sliceMin:sliceMax]

1. 我想我应该需要一个 hist 函数来绘制图表。虽然我有情节,但我不确定它是否是生成直方图的正确方法。

hist, bin_edges = np.histogram(voltages, bins=500, density=True)
hist = savgol_filter(hist, 51, 3)
bin_centres = (bin_edges[:-1] + bin_edges[1:])/2

到目前为止,我已经达到了。第三个峰值的幅度太低,这不是我所期望的。但是,如果我的期望是错误的,请纠正我。

这是我的直方图

我已经用以下代码更新了我的情节

labels = "hist"
if showGraph:
    plt.title("Datapoints Distribution over Voltage [mV]", )      
    plt.xlabel("Voltage [mV]")
    plt.ylabel("Data Points")
    plt.plot(hist, label=labels)
    plt.show()

2.(已编辑)我不知道为什么我的标签无法显示,您能纠正我吗?

3.(已编辑)此外,我想通过对直方图使用高斯函数来制作拟合曲线。但是有三个峰值,那么我应该如何使函数适合它们呢?

def gauss(x, *p):
A, mu, sigma = p
        return A*np.exp(-(x-mu)**2/(2.*sigma**2))

4.(已编辑)我意识到我还没有提到平均值。我想如果我可以找到峰值的最大值,那么我可以找到特定峰值的平均值。我需要先拟合高斯才能找到峰值,还是可以找到直线?是否要找到局部最大值以便我找到它?如果是,我该如何进行?

5.(已编辑)我知道如何从单个列表中找到标准差,如果我想做类似的逻辑,如何实现代码?

sample = [1,2,3,4,5,5,5,5,10]
standard_deviation = np.std(sample, ddof=1)
print(standard_deviation)

对建议的反馈:我尝试实现高斯拟合,以下是我导入的包。

from sklearn.mixture import GaussianMixture
import numpy as np
import matplotlib.pyplot as plt

这是高斯函数,我将我的 30 个数据集电压作为高斯混合拟合的参数,它打印了我们关于mu和的许多值variance

gmm = GaussianMixture(n_components=1)
gmm.fit(voltages)
print(gmm.means_, gmm.covariances_)
mu = gmm.means_[0][0]
variance = gmm.covariances_[0][0][0]
print(mu, variance)

我一一处理代码。第二行有错误:

fig, ax = plt.subplots(figsize=(6,6))
Xs = np.arange(min(voltages), max(voltages), 0.05)

具有多个元素的数组的真值是不明确的。使用 a.any() 或 a.all()

我从网上搜索到,用这个表示只有一个值,比如如果有[T,T,F,F,T],你可以有4种可能性。

我将代码编辑为:

Xs = np.arange(min(np.all(voltages)), max(np.all(voltages)), 0.05)

这给了我这个:

'numpy.bool_' 对象不可迭代

我知道它不是一个布尔对象。在这个阶段,我不知道如何进行高斯曲线拟合。任何人都可以为我提供另一种方法吗?

标签: pythonmatplotlibvisualization

解决方案


  1. 要绘制直方图,最普通的matplotlib函数hist是我的首选。基本上,如果我有一个 列表samples,那么我可以通过以下方式用 bin 绘制它们的直方图100
import matplotlib.pyplot as plt
plt.hist(samples, bins=100)
plt.show()
  1. 如果您想将正态分布拟合到您的数据中,最好的模型是高斯混合模型,您可以通过scikit-learn 的 GMM 页面找到更多信息。也就是说,这是我用来将奇异高斯分布拟合到数据集的代码。如果我想拟合k正态分布,我需要使用n_components=k. 我还包括了结果图:
from sklearn.mixture import GaussianMixture
import numpy as np
import matplotlib.pyplot as plt

data = np.random.uniform(-1,1, size=(800,1))
data += np.random.uniform(-1,1, size=(800,1))
gmm = GaussianMixture(n_components=1)
gmm.fit(data)
print(gmm.means_, gmm.covariances_)
mu = gmm.means_[0][0]
variance = gmm.covariances_[0][0][0]
print(mu, variance)
fig, ax = plt.subplots(figsize=(6,6))
Xs = np.arange(min(data), max(data), 0.05)
ys = 1.0/np.sqrt(2*np.pi*variance) * np.exp(-0.5/variance * (Xs + mu)**2)
ax.hist(data, bins=100, label='data')
px = ax.twinx()
px.plot(Xs, ys, c='r', linestyle='dotted', label='fit')
ax.legend()
px.legend(loc='upper left')
plt.show()

绘图结果

至于问题 3,我不确定您要捕获哪个轴的标准差。如果您想获得列的标准差,可以使用np.std(data, axis=1), 和axis=0用于逐行标准差。


推荐阅读