1.背景介绍
Python 是一种高级编程语言,它具有易用性、丰富的功能库、跨平台性、可扩展性等特点。作为一门现代化的通用计算机语言,Python 被广泛应用于数据分析、Web开发、机器学习、科学计算等领域。正如许多程序员都在编写 Python 代码一样,Python 的社区也正在蓬勃发展,日趋成熟。
作为一个程序员和技术专家,掌握 Python 技术栈是很重要的。本书试图通过对 Python 的一些基本概念、核心算法以及实际案例的演示,帮助读者更好地理解和掌握 Python 在科学计算方面的优势。
本书将从以下几个方面进行介绍:
-
NumPy 和 SciPy:这是两种开源的用于科学计算的 Python 库,它们提供诸如矩阵运算、线性代数、统计分析、信号处理、优化、插值、随机数生成等工具。本书将首先对这些库中的核心概念和使用方法进行简要介绍;
-
Matplotlib:这是另一款流行的数据可视化库,它提供了包括条形图、饼图、散点图、直方图等常见的绘图类型,并支持不同的后端。本书将详细介绍 Matplotlib 中的核心概念、使用方法和一些实例;
-
Pandas:这是一款开源的数据处理库,它提供了高性能的数据结构和数据分析工具,能轻松完成数据清洗、探索和整合工作。本书将详细介绍 Pandas 中的核心概念、使用方法和一些实例;
-
PyTorch 和 TensorFlow:这是两个开源的深度学习框架,它们提供了构建神经网络、训练模型、推理预测等高效率的工具。本书将介绍这两款框架的基本概念、使用方法和一些实例;
-
Scikit-learn:这是一款开源的机器学习库,它提供了各种机器学习算法,包括分类、回归、聚类、降维、嵌入、预处理等。本书将介绍 Scikit-learn 中一些常用的算法及其实现方式;
-
项目实践:本书将结合具体项目来展示如何利用 Python 在科学计算中解决实际的问题。例如,如何使用 Python 实现复杂的多元函数求根、如何用 Python 进行时间序列分析、如何使用 Python 进行文字处理、如何搭建推荐系统等。
2.核心概念与联系
本章节简单介绍 Python 的一些基本概念,并介绍相关库的概念。
2.1 Python 版本
目前最新的 Python 发行版是 Python 3.9 。它是当前版本的长期支持 (LTS) ,它的特性会逐渐与 Python 2 系列版本进行比较。Python 2 已经进入历史阶段,不再受到官方支持,所有重大更新、改进和新功能都会优先集中在 Python 3 上。
Python 2 和 3 在很多方面相似,但也存在一些差异。比如,语法上有些变化,模块名不同等等。为了能够同时兼容 Python 2 和 3 ,需要考虑采用适当的方式来编写代码。
2.2 数据类型
Python 支持多种数据类型,包括整数、浮点数、字符串、布尔值、列表、元组、字典、集合等。其中,布尔值和 NoneType 不属于内置数据类型。
2.2.1 整数 int
整数可以是无符号的或带符号的,取决于是否在数字前加上了符号 (+/-)。Python 可以自动识别整数类型,并且支持任意精度的整数。还可以使用位运算符对整数进行位操作,比如按位与 (&),按位或 (|),按位异或 (^) 和按位取反 (~)。
a = -1 # 带符号整数
b = +2 # 带符号整数
c = 0xff # 十六进制整数
d = 2**31 # 超出范围的整数
e = -(-d // abs(d)) # 对负数取绝对值再取负数,得到相同的值(取整)
print(e) # output: -2147483648
2.2.2 浮点数 float
Python 中单精度浮点数由 struct 模块定义。它只保留小数点后六位有效数字。
x = 3.14159 # 浮点数
y = 2.5E-2 # 科学计数法表示的浮点数
z = 3 * 3.14 / 2 # 浮点除法
w = x ** y # 幂运算
print(w) # output: 9.86960440109
2.2.3 复数 complex
Python 中的复数由 complex() 函数创建,实部和虚部之间用 j 或 J 表示。复数的乘法和加法遵循直觉上的定义规则。
a = 2+3j # 创建复数
b = a ** 2 # 复平方运算
c = b.real # 获取实部
d = b.imag # 获取虚部
print(c, d) # output: (-16.0) (-11.0)
2.2.4 字符串 str
字符串是不可变的 Unicode 字符序列。字符串用引号标识,可以用索引访问每一个字符。字符串可以拼接和重复。Python 没有单独的字符类型。
s = "Hello World" # 字符串
t = s[::-1] # 反转字符串
u = "%d plus %d equals %d" % (2, 3, 2+3) # 字符串模板
v = u.format(name="Alice", age=25) # 使用 format 方法格式化字符串
print(t, v) # output: dlroW olleH hello Alice is 25 years old
2.2.5 列表 list
列表是一个有序的元素序列,可以包含任意类型的对象。列表用方括号 [] 标识,可以根据位置访问或者修改元素。列表可以添加元素、删除元素、插入元素、排序元素等。
l = [1, 2, 3, 'four', False] # 列表
m = ['hello'] * 3 # 列表元素复制
n = l[::2] # 隔一取样切片
o = sorted(set(['apple', 'banana', 'orange'])) # 去重并排序
print(len(l), m, n, o) # output: 5 ['hello', 'hello', 'hello'] [1, 'four'] ['apple', 'orange', 'banana']
2.2.6 元组 tuple
元组是有序的元素序列,可以包含任意类型的对象。元组用圆括号 () 标识,可以根据位置访问元素。元组不能修改,但是可以包含可变的对象。
t = ('foo', 'bar') # 元组
u = t + ('baz', ) # 拼接元组
v = len(u) # 获取元组长度
print(type(u), v) # output: <class 'tuple'> 4
2.2.7 字典 dict
字典是一个无序的键值对映射表,可以包含任意类型的对象。字典用花括号 {} 标识,用冒号 : 分割键值。字典根据键查找对应的值。
d = {'a': 1, 'b': 2} # 字典
e = {k: v for k in d if v > 1} # 生成子字典
f = {v: k for k, v in e.items()} # 交换键值
g = d.get('c', 0) # 获取值,找不到返回默认值
h = set(e.keys()) & set(d.keys()) # 计算共同键
i = next((key for key in f if key not in h), '') # 查找没有共同键的键
print(e, f, g, i) # output: {'a': 1} {1: 'a'} 0 'c'
2.2.8 集合 set
集合是一个无序且不重复的元素序列。集合用花括号 {} 标识,元素间用逗号分隔。集合只能存储 hashable 对象。
s = {1, 2, 3, 3, 2, 1} # 集合
t = s | {4, 5, 6} # 合并集合
u = s - {1, 2, } # 集合差集
v = s ^ t # 集合对称差集
w = frozenset([1, 2, ]) # 将集合变为不可变集合
x = w.union({2, 3}) # 更新集合
print(sorted(list(s)), list(t), list(u), list(v), list(x)) # output: [1, 2, 3] [1, 2, 3, 4, 5, 6] [3] [4, 5, 6] [1, 2, 3]
2.3 控制流程语句
Python 提供了条件判断语句 if/elif/else、循环语句 for/while、迭代器和生成器、异常处理语句 try/except/finally。
2.3.1 if/elif/else
if/elif/else 是条件判断语句。条件表达式可以是任意的表达式,返回值为 True 或 False。如果表达式为 True,则执行该分支的代码;否则,继续判断下一条分支。
age = 20
if age >= 18:
print("You are an adult.")
elif age >= 12 and age <= 17:
print("You are a teenager.")
else:
print("You are a child.")
2.3.2 for/while
for/while 是循环语句。for 循环遍历列表、元组或其他可迭代对象的每个元素,while 循环则是根据条件判断循环体。break 语句可以提前退出循环,continue 语句跳过当前次循环。
fruits = ["apple", "banana", "orange"]
for fruit in fruits:
if fruit == "banana":
continue
elif fruit == "orange":
break
else:
print(fruit)
count = 0
total = 0
while count < len(fruits):
total += sum([ord(c)-ord('a'+1)+1 for c in fruits[count]])
count += 1
print(total)
2.3.3 iter() 和 next()
iter() 函数返回一个迭代器对象,next() 函数获取迭代器对象的下一个值,或触发 StopIteration 异常。
it = iter([1, 2, 3])
try:
while True:
value = next(it)
print(value)
except StopIteration:
pass
2.3.4 try/except/finally
try/except/finally 是异常处理语句。try 块中的代码可能会出现异常,则会跳到对应的 except 块中进行处理。finally 块中的代码总会被执行,无论是否出现异常。
try:
x = int(input("Enter a number:"))
result = 10 / x
print("Result:", result)
except ZeroDivisionError:
print("Invalid input!")
except ValueError:
print("Invalid input! Please enter a number.")
finally:
print("Program finished")
2.4 函数
函数是程序的主要组件之一,可以用来封装代码和重用代码。函数的定义需要指定函数名、参数列表、函数体。
def my_func(a, b):
"""This function adds two numbers"""
return a + b
result = my_func(1, 2) # Call the function with arguments
print(result) # Output: 3
help(my_func) # Get help about the function
2.4.1 参数
函数的参数可以是任意类型的数据,也可以没有参数。
def my_func():
print("This is a function without parameters")
def my_other_func(*args, **kwargs):
"""Function with variable length of positional and keyword args."""
for arg in args:
print(arg)
for key, val in kwargs.items():
print("%s=%s" % (key, val))
my_func() # Output: This is a function without parameters
my_other_func(1, 2, 3, name='John', city='New York') # Output: 1 2 3 John=John city=New York
2.4.2 默认参数
函数定义时,可以设置默认值,即某些参数在调用时可以省略,使用默认值。
def my_func(a, b=2, c=3):
"""Function with default values for some parameters."""
return a*b+c
result = my_func(1) # use only one argument and omit optional ones
print(result) # Output: 6
2.4.3 匿名函数 lambda
lambda 表达式是一个简单的单行函数。
add = lambda x, y: x + y
subtract = lambda x, y: x - y
multiply = lambda x, y: x * y
divide = lambda x, y: x / y if y!= 0 else 0
pow = lambda x, y: x ** y
print(add(2, 3))
print(subtract(5, 3))
print(multiply(2, 4))
print(divide(8, 2))
print(divide(8, 0))
print(pow(2, 3))
2.5 文件 I/O
Python 提供了文件 I/O 操作,可以读取和写入文本文件,读写二进制文件,以及打开和关闭文件句柄。
# Write to file
with open('file.txt', 'w') as f:
f.write('Hello world!\n')
# Read from file
with open('file.txt', 'r') as f:
data = f.read()
print(data)
# Append to file
with open('file.txt', 'a') as f:
f.write('Goodbye!\n')
3.NumPy 和 SciPy
NumPy 和 SciPy 是 Python 科学计算库,它们提供矩阵运算、线性代数、统计分析、信号处理、优化、插值、随机数生成等工具。
3.1 NumPy
NumPy 是 Python 科学计算的基础库,包含多种数学函数库和数据结构。NumPy 中的数组对象 ndarray 是一种多维矩阵,可以处理多维数据。数组对象在内存中以矢量形式存储,因此运算速度快,内存占用也少。
import numpy as np
# Create arrays
arr1 = np.array([1, 2, 3])
arr2 = np.array([[1, 2], [3, 4]])
arr3 = np.zeros((3, 3))
# Access elements
print(arr2[0][0]) # Output: 1
# Operations
sum_arr1 = arr1 + arr2
prod_arr1 = arr1 * arr2
mean_arr1 = arr1.mean()
std_dev_arr1 = arr1.std()
transpose_arr2 = arr2.T
dot_product_arr1_arr2 = np.dot(arr1, arr2)
# Print results
print("Sum array:", sum_arr1)
print("Product array:", prod_arr1)
print("Mean of array:", mean_arr1)
print("Standard deviation of array:", std_dev_arr1)
print("Transpose of matrix:", transpose_arr2)
print("Dot product of vectors:", dot_product_arr1_arr2)
3.2 SciPy
SciPy 是基于 NumPy 的科学计算库,提供更多的工具,包括最优化、积分、插值、矩阵求导和数值微分等。
from scipy import optimize
# Define objective function
def func(x):
return x**2 + 2*x - 1
# Find root using Brent's method
root = optimize.brentq(func, -1, 2)
# Print result
print("Root of equation:", root)
4.Matplotlib
Matplotlib 是 Python 可视化库,提供线性图、条形图、饼图、散点图、直方图等绘制类型,并支持不同的后端。
import matplotlib.pyplot as plt
# Plotting simple graph
plt.plot([1, 2, 3, 4], [1, 4, 9, 16])
plt.xlabel('X Label')
plt.ylabel('Y Label')
plt.title('Simple Graph')
plt.show()
# Scatter plot
x = [1, 2, 3, 4]
y = [1, 4, 9, 16]
plt.scatter(x, y)
plt.xlabel('X Label')
plt.ylabel('Y Label')
plt.title('Scatter Plot')
plt.show()
# Bar chart
x = ['A', 'B', 'C']
y = [1, 2, 3]
plt.bar(x, y)
plt.xlabel('Category')
plt.ylabel('Values')
plt.title('Bar Chart')
plt.show()
# Pie chart
labels = ['Apple', 'Banana', 'Orange']
sizes = [30, 15, 25]
colors = ['gold', 'yellowgreen', 'lightcoral']
explode = (0.1, 0, 0)
plt.pie(sizes, labels=labels, colors=colors, explode=explode, autopct='%1.1f%%', shadow=True, startangle=140)
plt.axis('equal')
plt.show()
5.Pandas
Pandas 是基于 NumPy 的数据处理库,提供高性能的数据结构和数据分析工具,能轻松完成数据清洗、探索和整合工作。
import pandas as pd
# Load dataset into dataframe
df = pd.read_csv('dataset.csv')
# Select columns
cols = df[['Name', 'Age']]
# Filter rows based on condition
filtered_rows = df[(df['Age'] >= 18) & (df['Salary'] >= 50000)]
# Group by category and apply aggregation functions
grouped_df = df.groupby('Gender')['Age'].agg(['min','max'])
# Merge datasets
merged_df = pd.merge(left=df1, right=df2, how='inner', left_on='id', right_on='user_id')
# Export data to CSV or Excel files
df.to_csv('new_dataset.csv', index=False)
df.to_excel('new_dataset.xlsx')
6.PyTorch 和 TensorFlow
PyTorch 和 TensorFlow 是两个开源的深度学习框架,它们提供了构建神经网络、训练模型、推理预测等高效率的工具。
import tensorflow as tf
# Create tensors
tensor1 = tf.constant([1, 2, 3])
tensor2 = tf.Variable([-1, 1, 0])
# Perform operations
sum_tensor1 = tensor1 + tensor2
mean_tensor2 = tf.reduce_mean(tensor2)
matmul_tensor1_tensor2 = tf.matmul(tf.expand_dims(tensor1, axis=-1), tf.expand_dims(tensor2, axis=0))
softmax_tensor2 = tf.nn.softmax(tensor2)
# Train model using GradientTape
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(10, activation='relu', input_shape=(None, 10)),
tf.keras.layers.Dropout(.2),
tf.keras.layers.Dense(1)
])
loss_fn = tf.keras.losses.MeanSquaredError()
optimizer = tf.keras.optimizers.Adam(learning_rate=.01)
@tf.function
def train_step(inputs, targets):
with tf.GradientTape() as tape:
predictions = model(inputs)
loss = loss_fn(targets, predictions)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return loss
# Use model for inference
outputs = model(inputs)
7.Scikit-learn
Scikit-learn 是一款开源的机器学习库,提供了各种机器学习算法,包括分类、回归、聚类、降维、嵌入、预处理等。
from sklearn.linear_model import LinearRegression
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# Create sample data
x = [[1, 2], [3, 4]]
y = [1, 2]
# Fit linear regression model
regressor = LinearRegression().fit(x, y)
# Apply clustering algorithm
km = KMeans(n_clusters=2).fit(x)
# Normalize data
scaler = StandardScaler().fit(x)
normalized_x = scaler.transform(x)
8.项目实践
本章节介绍几种典型的科学计算项目,包括复杂的多元函数求根、时间序列分析、文字处理、推荐系统等。
8.1 多元函数求根
多元函数的求根通常使用优化算法,比如梯度下降、牛顿法等。本例使用 BFGS 算法求解 的根。
from scipy.optimize import minimize
# Objective function
def obj_fun(x):
return x[0]**2 + x[1]**2
# Initial guess
init_guess = [1, 1]
# Solve multi-dimensional problem using BFGS
solution = minimize(obj_fun, init_guess, method='BFGS')
# Extract solution
root = solution.x
# Print result
print("Root of equation:", root)
8.2 时序分析
时序分析通常需要对时间序列进行分析,比如滞后影响分析、季节性影响分析、周期性影响分析等。本例使用移动平均模型进行时序分析,模拟股价走势的波动情况。
import pandas as pd
import matplotlib.pyplot as plt
# Generate random time series data
dates = pd.date_range('2020-01-01', periods=100, freq='D')
prices = pd.Series(np.random.normal(loc=100, scale=10, size=100), index=dates)
# Calculate moving average
window_size = 10
moving_avg = prices.rolling(window_size).mean()
# Visualize data
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(prices)
ax.plot(moving_avg, label='Moving Average')
ax.legend()
ax.set_title('Time Series Analysis Example')
ax.set_xlabel('Date')
ax.set_ylabel('Stock Price')
ax.grid()
plt.show()
8.3 文字处理
计算机的处理能力很强,可以处理大量的文本信息。本例使用词频分析进行中文文档的关键词提取。
from jieba import analyse
from collections import Counter
text = '''
Python 是一种高级编程语言,具有易用性、丰富的功能库、跨平台性、可扩展性等特点。作为一门现代化的通用计算机语言,Python 被广泛应用于数据分析、Web开发、机器学习、科学计算等领域。正如许多程序员都在编写 Python 代码一样,Python 的社区也正在蓬勃发展,日趋成熟。
'''
keywords = analyse.extract_tags(text, topK=10, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))
word_counts = Counter(keywords)
print(keywords)
print(word_counts)
8.4 推荐系统
推荐系统是个热门话题,它的目的是向用户提供一些感兴趣的内容或商品。本例使用协同过滤算法进行推荐系统,给出一个用户的潜在兴趣。
import pandas as pd
import surprise
# Load movielens dataset
ratings_file = './ml-latest-small/ratings.csv'
movies_file = './ml-latest-small/movies.csv'
ratings_df = pd.read_csv(ratings_file)
movies_df = pd.read_csv(movies_file)[['movieId', 'title']]
ratings_df = ratings_df.join(movies_df.set_index('movieId'), on='movieId').dropna()
ratings_df = ratings_df.sample(frac=1.)
reader = surprise.Reader(rating_scale=(0., 5.))
data = surprise.Dataset.load_from_df(ratings_df[['userId','movieId', 'rating']], reader)
trainset, testset = surprise.model_selection.train_test_split(data, test_size=.2)
algo = surprise.SVD(n_factors=20, lr_all=0.01, reg_all=0.01)
algo.fit(trainset)
# Recommend movies to user with ID=20
user_id = 20
item_ids = ratings_df[ratings_df['userId']==user_id]['movieId']
predictions = algo.predict(str(user_id), item_ids)
top_n = [pred[0] for pred in sorted(predictions, reverse=True)[:10]]
recommendations_df = movies_df.join(pd.DataFrame({'predicted_rating': [prediction[3] for prediction in predictions]})).iloc[top_n].sort_values(by=['predicted_rating'], ascending=False)
print("Recommended Movies:")
print(recommendations_df[['title', 'predicted_rating']])