σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academy学习路线
Ctrl K
AO
+1.2k 位学习者
登录加入 ↗
学习路线
AO
+1.2k 位学习者
登录
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python 学习路线›模块 2 · 用于市场数据的 NumPy 与 pandas›主题 2.5·~40分钟入门

pandas Series

路线进度模块 2/11 · 主题 5/20
2.5 pandas Series
—实验得分— / 100总 XP—连续天数—

带标签的数组

pandas Series 是一维数组,其中每个值都带有标签,标签保存在 Series 的索引里。你不必记住位置 1 是微软,而是直接请求 prices["MSFT"]。Series 有 name,像 NumPy 数组一样有 dtype,也支持同样的整数组运算,所以 prices * 2、prices.mean() 和 prices > 180 都能用。按惯例用 import pandas as pd 导入 pandas,它建立在前面几节学过的 NumPy 之上。

import pandas as pd

prices = pd.Series([184.25, 410.2, 171.0], index=["AAPL", "MSFT", "GOOG"], name="price")
print(prices)
# AAPL    184.25
# MSFT    410.20
# GOOG    171.00
# Name: price, dtype: float64

print(prices["AAPL"], prices.iloc[1])    # 184.25 410.2   by label, by position
print(prices.index.tolist())             # ['AAPL', 'MSFT', 'GOOG']
print(prices[prices > 180])              # keeps AAPL and MSFT, labels intact
print(prices.mean(), prices.idxmax())    # 255.15 MSFT

# A dict also builds a Series: keys become the index
print(pd.Series({"AAPL": 1, "MSFT": 2}))

对齐:运算按标签匹配,而不是按位置

组合两个 Series 时,pandas 会先按标签对齐。只出现在其中一个里的标签,结果中是 NaN(非数,缺失值的标记),结果的索引是两个索引的并集。这正是合并不同账户里的持仓所需要的。使用 a.add(b, fill_value=0) 可把缺失的标签当作 0,而不是产生 NaN。按标签读取也与 NumPy 不同:s["MSFT"] 按标签,s.iloc[1] 按位置,不存在的标签会引发 KeyError。

import pandas as pd

a = pd.Series([100, 200], index=["AAPL", "MSFT"])
b = pd.Series([50, 10], index=["MSFT", "GOOG"])

print(a + b)
# AAPL      NaN
# GOOG      NaN
# MSFT    250.0

print(a.add(b, fill_value=0))
# AAPL    100.0
# GOOG     10.0
# MSFT    250.0

# Selecting by a list of labels, and asking for one that is missing
prices = pd.Series([184.25, 410.2], index=["AAPL", "MSFT"])
print(prices.reindex(["MSFT", "TSLA"]).tolist())   # [410.2, nan]

排序、排名与基准化

s.sort_values(ascending=False) 按值排序并带着标签一起移动,s.sort_index() 按标签排序,s.abs() 取绝对值。排序加切片能找出变动最大的:r.abs().sort_values(ascending=False).index[:3] 给出绝对收益最大的三个标签。要比较价格水平不同的资产,可在起点把各自基准化到 100:s / s.iloc[0] * 100,它会保留索引和名称。缺失值(NaN)会被 sum、mean 等跳过;s.isna() 可标出它们。

import pandas as pd

r = pd.Series([0.01, -0.03, 0.02], index=["x", "y", "z"])
print(r.abs().sort_values(ascending=False))
# y    0.03
# z    0.02
# x    0.01
# dtype: float64

prices = pd.Series([184.25, 410.2, 171.0], index=["AAPL", "MSFT", "GOOG"], name="price")
print(prices / prices.iloc[0] * 100)           # rebased to 100 at the first value
# AAPL    100.000000
# MSFT    222.632293
# GOOG     92.808684
# Name: price, dtype: float64

gappy = pd.Series([1.0, None, 3.0])
print(gappy.sum(), gappy.mean(), gappy.isna().tolist())   # 4.0 2.0 [False, True, False]
import pandas as pd

# A stray space and a lower-case letter make "the same" symbol two labels
raw = pd.Series([1, 2], index=["AAPL", "aapl "])
print(raw.index.is_unique)                     # True: they look different

raw.index = raw.index.str.strip().str.upper()  # clean the labels
print(raw.index.is_unique)                     # False: now both are "AAPL"
print(raw["AAPL"].tolist())                    # [1, 2]   a duplicate label returns a Series

merged = raw.groupby(level=0).sum()            # combine duplicates (groupby comes soon)
print(merged.to_dict())                        # {'AAPL': 3}
标签也是数据:重复与拼写错误对齐的质量取决于标签。"AAPL" 和 "aapl " 是不同的标签,所以拼写错误会悄悄产生 NaN 行;组合之前先清理标签(strip、upper)。索引可能含有重复值,这时 s["AAPL"] 返回的是 Series 而不是一个值;对于应当每个标签只有一个值的数据,要检查 s.index.is_unique。运算返回新的 Series,原对象保持不变,实验的测试检查的正是这种行为。
  • pd.Series(values, index=labels, name=...);按标签 s["A"] 或按位置 s.iloc[0] 读取。
  • 运算按标签对齐(并集索引,缺失为 NaN);a.add(b, fill_value=0) 把缺口当作 0。
  • sort_values、abs、idxmax、s / s.iloc[0] * 100;结果是新 Series,原对象不变。

下一节:pandas DataFrame,由共享同一索引的 Series 组成的表格。

实验:评分内容

  • 用 price_series 按代码给价格贴标签25 分
  • 用 total_exposure 按标签合并两个账户25 分
  • 用 top_movers 找出波动最大的标的25 分
  • 用 rebase_to_100 把每个价格换算为基期 10025 分
资源管理器 · lab-38-1
▾ lab-38-1
…
bash · 浏览器内
learner@quantcraft:~/lab-38-1$
Python 尚未加载PythonLn 1, Col 1Spaces: 4UTF-8

要重置此主题吗?

lab-38-1 中的所有内容将恢复为初始文件,终端也会被清空。你当前的解答将丢失,且无法撤销。

将被重置
  • main.py → 初始代码
  • 终端历史与测试输出
  • 未提交的更改
将被保留
  • 实验最高得分
  • 你的 XP 与连续天数
  • 讲解进度与笔记

登录后即可运行你的代码。

所有讲解均可免费阅读。创建账户或登录后,即可运行代码、运行测试并提交此实验。

  • 浏览器内 IDE 与 bash 终端,无需安装
  • 即时评分、XP 以及你在学习路线中的位置
创建账户登录
或
使用 GitHub 继续