σμ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.7·~40分钟入门

用 loc 和 iloc 选取数据

路线进度模块 2/11 · 主题 7/20
2.7 用 loc 和 iloc 选取数据
—实验得分— / 100总 XP—连续天数—

指向数据的两种方式:按标签和按位置

DataFrame 有两种寻址方式,把它们搞混是 pandas 最常见的 bug。.loc 按标签选择:行用索引中的标签,列用列名。.iloc 按整数位置选择,从 0 开始计数,和列表、NumPy 数组一样。两者都接收 [行, 列]:df.loc["AAPL", "price"] 是一个值,df.iloc[0, 0] 是第一行第一列的值。省略第二部分表示取整行:df.loc["AAPL"] 是 AAPL 这一行(Series)。

import pandas as pd

df = pd.DataFrame(
    {"price": [184.25, 410.2, 171.0, 251.0],
     "volume": [200, 50, 300, 120],
     "sector": ["tech", "tech", "tech", "auto"]},
    index=["AAPL", "MSFT", "GOOG", "TSLA"],
)

print(df.loc["AAPL", "price"], df.iloc[0, 0])     # 184.25 184.25   same cell, two addresses
print(df.loc["TSLA"].to_dict())                    # {'price': 251.0, 'volume': 120, 'sector': 'auto'}
print(df.iloc[-1].to_dict())                       # the same row: position -1 is the last
print(df.loc[["TSLA", "AAPL"], "price"])           # a list of labels picks in that order
# TSLA    251.00
# AAPL    184.25
# Name: price, dtype: float64

try:
    df.loc["XXX", "price"]                         # a label that does not exist
except KeyError as error:
    print("KeyError", error)                       # KeyError 'XXX'

切片:标签切片包含终点

两种方式下切片的行为不同。位置切片 df.iloc[1:3] 遵循 Python 的规则,不含终点:即位置 1 和 2。标签切片 df.loc["MSFT":"TSLA"] 包含两端的标签,因为标签没有天然的“下一个”。标签切片遵循索引当前的顺序,索引不必已排序。对于列,传入列表(["price", "volume"])即可按给定顺序选取。忘了自己用的是哪种方式,会在没有任何报错的情况下得到偏差一位的结果。

import pandas as pd

df = pd.DataFrame(
    {"price": [184.25, 410.2, 171.0, 251.0], "volume": [200, 50, 300, 120]},
    index=["AAPL", "MSFT", "GOOG", "TSLA"],
)

print(df.iloc[1:3])                              # positions 1 and 2: the end is excluded
#        price  volume
# MSFT   410.2      50
# GOOG   171.0     300

print(df.loc["MSFT":"TSLA", ["volume", "price"]])    # labels MSFT..TSLA: the end is included
#       volume  price
# MSFT      50  410.2
# GOOG     300  171.0
# TSLA     120  251.0

print(df.iloc[:, 0].tolist())                    # the first column, by position
# [184.25, 410.2, 171.0, 251.0]

用 loc 做条件选择与赋值

.loc 的行部分还可以接收布尔掩码:df.loc[df["volume"] > 100, "price"] 一步就得到满足条件的行的价格列。.loc 也是对选定部分赋值的方式:df.loc["MSFT", "price"] = 1.0 修改一个单元格,df.loc[df["volume"] < 100, "volume"] = 0 修改所有符合条件的行。避免 df[df["volume"] < 100]["volume"] = 0 这样的链式写法:它作用在一个临时副本上。在 pandas 3 中,派生出的表绝不会改动原表,所以要在函数里修改表,应先 df.copy(),用 .loc 赋值,再返回该副本。

import pandas as pd

df = pd.DataFrame(
    {"price": [184.25, 410.2, 171.0, 251.0], "volume": [200, 50, 300, 120]},
    index=["AAPL", "MSFT", "GOOG", "TSLA"],
)

print(df.loc[df["volume"] > 100, "price"])       # a Boolean mask for rows, a label for the column
# AAPL    184.25
# GOOG    171.00
# TSLA    251.00
# Name: price, dtype: float64

def with_price(frame, symbol, price):
    out = frame.copy()                           # never edit the caller's table
    out.loc[symbol, "price"] = price
    return out

changed = with_price(df, "MSFT", 1.0)
print(changed.loc["MSFT", "price"], df.loc["MSFT", "price"])   # 1.0 410.2

fixed = df.copy()
fixed.loc[fixed["volume"] < 100, "volume"] = 0   # assign to all matching rows at once
print(fixed["volume"].tolist())                  # [200, 0, 300, 120]
import pandas as pd

# Integer labels are labels, not positions: a classic trap
d = pd.DataFrame({"x": [1.0, 2.0, 3.0]}, index=[10, 20, 30])

print(d.loc[20, "x"], d.iloc[0, 0])        # 2.0 1.0    label 20 is the second row
print(d.loc[10:20]["x"].tolist())          # [1.0, 2.0] labels 10 through 20, end included
print(d.iloc[0:2]["x"].tolist())           # [1.0, 2.0] positions 0 and 1, end excluded

try:
    d.loc[0, "x"]                          # there is no label 0, even though position 0 exists
except KeyError as error:
    print("KeyError", error)               # KeyError 0
选对工具,并优先使用标签知道名称(代码、日期、列名)时用 .loc,只有位置本身就是重点时(“最后一行”“前三行”)才用 .iloc。基于标签的代码在行被重新排序后依然有效;基于位置的代码则会悄悄开始选到别的行。单独的 df[...] 是有多种含义的简写(列、列列表、行掩码),所以在重要的函数里要明确写出 .loc 或 .iloc。实验有意要求使用其中之一。
  • df.loc[行标签, 列标签] 按标签;df.iloc[行位置, 列位置] 按从 0 开始的位置。
  • iloc 切片不含终点;loc 标签切片包含终点;缺失的标签会引发 KeyError。
  • df.loc[mask, "col"] 筛选并选取;在 .copy() 上用 .loc 赋值并返回。

下一节:groupby 与聚合,把表格分成若干组并分别汇总。

实验:评分内容

  • 用 price_of 按代码查一个价格25 分
  • 用 label_range 取两个代码之间的行25 分
  • 用 position_range 按位置取行25 分
  • 用 set_price 在副本中修正一个价格25 分
资源管理器 · lab-40-1
▾ lab-40-1
…
bash · 浏览器内
learner@quantcraft:~/lab-40-1$
Python 尚未加载PythonLn 1, Col 1Spaces: 4UTF-8

要重置此主题吗?

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

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

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

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

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