Python中如何逐行更新DataFrame期权字段而非整列?
问题描述
我是一名自学的业余开发者,近期在处理期权数据时遇到难题:使用for循环解析期权合约信息时逻辑正常,但尝试为Pandas DataFrame添加contract_date、contract_type、strike_price三个字段时,循环会将整列更新为同一值,而非每行对应不同的正确值。我尝试了append、concat等多种方法,要么结果依旧错误,要么出现报错,请问正确的逐行更新DataFrame的方式是什么?
原代码
from numpy import dtype import pandas as pd import requests import urllib.parse from datetime import datetime from dateutil import tz s = requests.Session() headers = { #match headers on API request 'Accept':'*', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } #print('Enter a Ticker to Pull Data From') #ticker = input() ticker = 'SPY' tickerurl = f'https://cdn.cboe.com/api/global/delayed_quotes/options/{ticker}.json' data = s.get(tickerurl).json() lookupdata = data['data']['options'] df = pd.json_normalize(data['data']['options']) df['ticker'] = ticker for contract in lookupdata: y = contract['option'].replace(ticker,'') contract_date = f'20{y[0:2]}-{y[2:4]}-{y[4:6]}' z = y.replace(y[0:6],'') contract_type = "Call" if z[0] == 'C' else "Put" strikeprice = z.replace(z[0],'') strike_price = float(strikeprice)/1000 df['contract_date'] = contract_date df['contract_type'] = contract_type df['strike_price'] = strike_price print(df)
尝试的错误代码
from numpy import dtype import pandas as pd import requests import urllib.parse from datetime import datetime from dateutil import tz s = requests.Session() headers = { #match headers on API request 'Accept':'*', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } #print('Enter a Ticker to Pull Data From') #ticker = input() ticker = 'SPY' tickerurl = f'https://cdn.cboe.com/api/global/delayed_quotes/options/{ticker}.json' data = s.get(tickerurl).json() lookupdata = data['data']['options'] df = pd.json_normalize(data['data']['options']) df['ticker'] = ticker df2 = pd.DataFrame() for contract in lookupdata: y = contract['option'].replace(ticker,'') contract_date = f'20{y[0:2]}-{y[2:4]}-{y[4:6]}' z = y.replace(y[0:6],'') contract_type = "Call" if z[0] == 'C' else "Put" strikeprice = z.replace(z[0],'') strike_price = float(strikeprice)/1000 df['contract_date'] = contract_date df['contract_type'] = contract_type df['strike_price'] = strike_price df2 = df.append(df2) print(df2) # tried the following as well: # df2.append(df) #df2 = pd.concat(df2) #print(df2) # gives the error TypeError: first argument must be an iterable of pandas objects, you passed an object of type "DataFrame" #trying the following gives a key error on contract_date # df2.append(df) # df2 = pd.concat(df2['contract_date']['contract_type'][strike_price]) #print(df2) # df2.append(df) # df2 = #pd.concat((df2['contract_date'],df2['contract_type'],df2['strike_price']), #ignore_index=True) #print(df2)
解决方案
错误根源
原代码中df['contract_date'] = contract_date这类写法是将整列赋值为当前循环的单个值,循环结束后整列只会保留最后一个合约的计算结果;而错误代码里的append/concat用法完全偏离需求,要么重复追加错误的整列数据,要么因参数格式错误报错。
正确写法1:生成列表批量赋值
先通过循环收集每行的计算结果到列表,再一次性赋值给DataFrame,效率高且逻辑清晰:
from numpy import dtype import pandas as pd import requests import urllib.parse from datetime import datetime from dateutil import tz s = requests.Session() headers = { 'Accept':'*', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } ticker = 'SPY' tickerurl = f'https://cdn.cboe.com/api/global/delayed_quotes/options/{ticker}.json' data = s.get(tickerurl).json() lookupdata = data['data']['options'] df = pd.json_normalize(data['data']['options']) df['ticker'] = ticker # 初始化空列表存储每行结果 contract_dates = [] contract_types = [] strike_prices = [] for contract in lookupdata: y = contract['option'].replace(ticker,'') contract_date = f'20{y[0:2]}-{y[2:4]}-{y[4:6]}' z = y.replace(y[0:6],'') contract_type = "Call" if z[0] == 'C' else "Put" strikeprice = z.replace(z[0],'') strike_price = float(strikeprice)/1000 # 将当前合约结果追加到对应列表 contract_dates.append(contract_date) contract_types.append(contract_type) strike_prices.append(strike_price) # 批量赋值给DataFrame的列 df['contract_date'] = contract_dates df['contract_type'] = contract_types df['strike_price'] = strike_prices print(df)
正确写法2:使用apply函数(更简洁)
利用Pandas的apply方法对每行数据进行解析,避免显式循环:
from numpy import dtype import pandas as pd import requests import urllib.parse from datetime import datetime from dateutil import tz s = requests.Session() headers = { 'Accept':'*', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } ticker = 'SPY' tickerurl = f'https://cdn.cboe.com/api/global/delayed_quotes/options/{ticker}.json' data = s.get(tickerurl).json() df = pd.json_normalize(data['data']['options']) df['ticker'] = ticker # 定义解析单个期权合约的函数 def parse_option(row): option_str = row['option'].replace(ticker, '') # 解析合约日期 contract_date = f'20{option_str[0:2]}-{option_str[2:4]}-{option_str[4:6]}' # 解析合约类型和行权价 rest = option_str[6:] contract_type = "Call" if rest[0] == 'C' else "Put" strike_price = float(rest[1:])/1000 return pd.Series([contract_date, contract_type, strike_price], index=['contract_date', 'contract_type', 'strike_price']) # 应用函数并合并到原DataFrame df = pd.concat([df, df.apply(parse_option, axis=1)], axis=1) print(df)
内容的提问来源于stack exchange,提问作者user1470034
相关产品推荐
相关产品推荐

