Python入门实战:Python科学计算基础

27 阅读9分钟

1.背景介绍

Python 是一种高级编程语言,它具有易用性、丰富的功能库、跨平台性、可扩展性等特点。作为一门现代化的通用计算机语言,Python 被广泛应用于数据分析、Web开发、机器学习、科学计算等领域。正如许多程序员都在编写 Python 代码一样,Python 的社区也正在蓬勃发展,日趋成熟。

作为一个程序员和技术专家,掌握 Python 技术栈是很重要的。本书试图通过对 Python 的一些基本概念、核心算法以及实际案例的演示,帮助读者更好地理解和掌握 Python 在科学计算方面的优势。

本书将从以下几个方面进行介绍:

  1. NumPy 和 SciPy:这是两种开源的用于科学计算的 Python 库,它们提供诸如矩阵运算、线性代数、统计分析、信号处理、优化、插值、随机数生成等工具。本书将首先对这些库中的核心概念和使用方法进行简要介绍;

  2. Matplotlib:这是另一款流行的数据可视化库,它提供了包括条形图、饼图、散点图、直方图等常见的绘图类型,并支持不同的后端。本书将详细介绍 Matplotlib 中的核心概念、使用方法和一些实例;

  3. Pandas:这是一款开源的数据处理库,它提供了高性能的数据结构和数据分析工具,能轻松完成数据清洗、探索和整合工作。本书将详细介绍 Pandas 中的核心概念、使用方法和一些实例;

  4. PyTorch 和 TensorFlow:这是两个开源的深度学习框架,它们提供了构建神经网络、训练模型、推理预测等高效率的工具。本书将介绍这两款框架的基本概念、使用方法和一些实例;

  5. Scikit-learn:这是一款开源的机器学习库,它提供了各种机器学习算法,包括分类、回归、聚类、降维、嵌入、预处理等。本书将介绍 Scikit-learn 中一些常用的算法及其实现方式;

  6. 项目实践:本书将结合具体项目来展示如何利用 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 算法求解 f(x,y)=x2+y2f(x, y)=x^2+y^2 的根。

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']])