Pandas计算日收盘价区间时出现“Wrong number of items passed 2”错误排查
先给大家还原下场景:我有一份按10分钟频率记录的行情数据,结构大概是这样的(简化后示例):
import pandas as pd import numpy as np data = { 'Date': ['2019-06-20 07:00:00', '2019-06-20 07:05:00', '2019-06-20 07:10:00', '2019-06-21 07:00:00', '2019-06-21 07:05:00', '2019-06-21 07:10:00', '2019-06-24 07:00:00', '2019-06-24 07:05:00', '2019-06-24 07:10:00', '2019-06-25 07:00:00', '2019-06-25 07:05:00', '2019-06-25 07:10:00', '2019-06-26 07:00:00'], 'Close': [2927.25, 2927.00, 2926.75, 2932.25, 2932.25, 2931.00, 2941.75, 2942.25, 2941.50, 2925.50, 2926.50, 2926.50, 2903.25] } df = pd.DataFrame(data) df['Date'] = pd.to_datetime(df['Date'])
我想要计算每日收盘价的区间,于是按日期分组并聚合最小、最大值:
rangeofday = df.groupby(pd.Grouper(key='Date', freq='1D')).agg({'Close':[np.min, np.max]}) rangeofday = rangeofday.dropna()
结果得到了一个多级列索引的DataFrame,没法直接用rangeofday.amin或者rangeofday.Closeamin访问数据。我尝试计算区间值时,写了这段代码:
rangeofday['range'] = (rangeofday.iloc[:, [0]] - rangeofday.iloc[:, [1]])/0.25
结果直接报错:Wrong number of items passed 2, placement implies 1。下面给大家拆解下这个错误的原因,以及几种解决办法。
错误含义是什么?
这个报错的核心很简单:你试图把一个二维的DataFrame结果,赋值给一个单一的列。
当你用iloc[:, [0]]这种写法时(注意内层的方括号[0]),得到的是一个保留了列索引的二维DataFrame,而不是一维的Series。两个这样的DataFrame相减后,结果还是一个二维的DataFrame,但rangeofday['range']需要的是一个一维的Series。Pandas就会提示你:“你传了一个二维结构(相当于2个元素维度),但我这里只需要一维的”。
怎么解决?
给大家分享三种实用的解决方法,按需选择:
方法1:修改iloc索引,获取一维Series
把iloc[:, [0]]改成iloc[:, 0](去掉内层的方括号),这样得到的就是一维的Series,相减后结果也是Series,可以直接赋值给新列:
rangeofday['range'] = (rangeofday.iloc[:, 0] - rangeofday.iloc[:, 1])/0.25
方法2:利用多级列索引直接访问
既然已经是多级列索引,咱们可以直接通过层级定位,代码可读性更高:
# 写法一:通过层级依次访问 rangeofday['range'] = (rangeofday['Close']['amin'] - rangeofday['Close']['amax'])/0.25 # 写法二:用元组形式指定多级索引,更严谨(避免列名冲突时出错) rangeofday['range'] = (rangeofday[('Close', 'amin')] - rangeofday[('Close', 'amax')])/0.25
方法3:聚合时重命名,避免多级索引
最省心的办法其实是在分组聚合的时候,直接给聚合结果指定列名,这样得到的就是普通的单级列索引,后续操作完全不用纠结多级索引的问题:
# 聚合时直接命名结果列,生成单级索引DataFrame rangeofday = df.groupby(pd.Grouper(key='Date', freq='1D')).agg( close_min=('Close', np.min), close_max=('Close', np.max) ).dropna() # 直接计算区间值,跟操作普通DataFrame完全一样 rangeofday['range'] = (rangeofday['close_min'] - rangeofday['close_max'])/0.25
内容的提问来源于stack exchange,提问作者Mark T

