置頂

我的 VPython 教學文件 (HackMD 版本)

VPython 教學文件目錄 安裝及測試 基本語法 等速度直線運動 自由落下 終端速度 水平抛射 使用For迴圈計算水平抛射資料 斜向抛射 圓周運動 簡諧運動 單擺 木塊彈簧系統分離 重力及簡諧 行星運動 相疊木塊 雙重簡諧運動 一維彈性碰撞 ...

熱門文章

2019年8月8日 星期四

使用 numpy.genfromtxt 從文字檔中讀取資料

作者:王一哲
日期:2019/8/8




假設某人儲存資料時不是用csv檔,而是使用數量不一致的空格分格資料,我們將前一篇文章〈最接近直線〉的數據排列成底下這樣再儲存為文字檔data.txt。

index   x  errx   y     erry
    0   1.0  0.1      4.9   0.5
 1  2.0   0.1    6.9  0.5
2   3.0  0.1     9.0      0.5
  3   4.0    0.1  11.1   0.6
   4  5.0   0.1  13.2   0.6
 5  6.0   0.2    15.2     0.8
6 7.0 0.2  16.9    0.8
  7  8.0  0.2     18.9      0.8
 8    9.0   0.2  20.9   0.8
9   10.0  0.2   22.8    0.8

我絕對不會用這樣的格式儲存資料,但如果真的遇到這種狀況還是有辦法解決,只要使用numpy.genfromtxt即可,語法為

np.genfromtxt([資料檔名稱], dtype=[資料格式], unpack=[True 或 False], 
              skip_header=[列數], usecols=[欄位索引值])

其中資料格式預設值為float、unpack預設值為False、skip_header預設值為0、usecols預設值為None,詳細的用法請參考官方說明書



為了方便比較讀取資料的效果,我們使用前一篇文章〈最接近直線〉的數據及程式碼,但是將讀取資料的方法從numpy.loadtxt改成numpy.genfromtxt,程式碼如下

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

# 從 data.csv 讀取資料
x, errx, y, erry = np.genfromtxt('data.txt', dtype=float, unpack=True, skip_header=1, usecols=(1, 2, 3, 4))

# 計算最接近直線的斜率、截距及不準量
popt, pcov = curve_fit(lambda x, a, b: a*x+b, x, y, sigma=erry, absolute_sigma=True)

print("slope: %.12f +/- %.12f" % (popt[0], np.sqrt(pcov[0, 0])))
print("intercept: %.12f +/- %.12f" % (popt[1], np.sqrt(pcov[1, 1])))

# 計算最接近直線的R平方值
cor = np.corrcoef(x, y)[0, 1]
print("r-squared: %.12f" % cor**2)

# 建立繪圖物件
plt.figure(figsize=(6, 4.5), dpi=72)
plt.xlabel('x', fontsize=14)
plt.ylabel('y', fontsize=14)
plt.grid(color='grey', linestyle='--', linewidth=1)
plt.plot(x, y, color='blue', marker='o', markersize=10, linestyle='')
# 加上 error bar
plt.errorbar(x, y, xerr=errx, yerr=erry, color='black', fmt='o', capsize=4, markersize=0, linewidth=1)
# 加上最接近直線
line = popt[0]*x + popt[1]
plt.plot(x, line, color='red', marker='', linestyle='-', linewidth=2)

# 儲存、顯示圖片
plt.savefig('genfromtxt.svg')
plt.savefig('genfromtxt.png')
plt.show()



其實只改了第6行

x, errx, y, erry = np.genfromtxt('data.txt', dtype=float, unpack=True, skip_header=1, usecols=(1, 2, 3, 4))

從文字檔data.txt中讀取資料,資料格式為float,將資料依照欄位拆開,忽略第1行的文字,將第1、2、3、4欄的資料分別存入陣列x、errx、y、erry。


2021/7/15 補充

第6行也可以改成以下的寫法,效果一樣。
data = np.genfromtxt('data.txt', names=True)
x, errx, y, erry = data['x'], data['errx'], data['y'], data['erry']



線性擬合計算結果以及最後繪製的XY散佈圖與前一篇文章一模一樣,應該成功地解決了一個奇怪的要求。

$$ a = 1.997966995944 \pm 0.071531035658 $$
$$ b = 2.991771672485 \pm 0.371842522314 $$
$$ R^2 = 0.999497575579 $$


用 matplotlib 繪製的XY散佈圖




HackMD 版本連結:https://hackmd.io/@yizhewang/HyFxPWKXB

沒有留言:

張貼留言