我有一个带有2级Multiindex的数据框:
ix = pd.MultiIndex.from_tuples(list(enumerate(np.random.choice(['A', 'B'], 5))))
df = pd.DataFrame({'Val': np.random.randint(0, 30, 5)}, index=ix).unstack().fillna(0)
df
Val
A B
0 27 0
1 0 3
2 0 7
3 9 0
4 0 19
我想为每个现有的子级('A'
和'B'
)添加一列,该列等于Val
列的一半。我的直觉是做
df['Half_val'] = df.Val / 2
,提供ValueError: Wrong number of items passed 2, placement implies 1
例外。
我可以手动执行
res = df.Val / 2
df.loc[:, ('Half_val', 'A')] = res.A
df.loc[:, ('Half_val', 'B')] = res.B
给出了我之后的内容:
>>> df
Val Half_val
A B A B
0 27 0 13.5 0.0
1 0 3 0.0 1.5
2 0 7 0.0 3.5
3 9 0 4.5 0.0
4 0 19 0.0 9.5
是否有一种不那么详细,更惯用的方式来制作这样的多索引列分配(尤其是我不必在左侧明确指定每个子级的那个)?
编辑:
我忘了提到尝试
res = df.Val / 2
df.loc[:, res.columns] = res
提供KeyError: "['A' 'B'] not in index"
例外。
编辑2 如果解决方案允许数据帧中的伪混合级别列,那将是很好的。在我的例子中,我可以做
In [5]: df['C'] = 'a'
In [6]: df
Out[6]:
Val C
A B
0 4 0 a
1 0 10 a
2 0 4 a
3 21 0 a
4 0 14 a
添加一个单一级别的列。但由于该列已经有2个级别,因此它似乎给出了一个隐含的第二级空字符串
In [9]: list(df)
Out[9]: [('Val', 'A'), ('Val', 'B'), ('C', '')]
当我尝试下面提供的解决方案时,单级C
列似乎打破了它:
In [7]: pd.concat([df,df['Val']/2],axis=1,keys=['Val', 'C', 'Half'])
==> AssertionError: Cannot concat indices that do not have the same number of levels
keys
参数是否有一些技巧可以传递,或者我是否需要为C
提供不同的虚拟值以用于第二级(因为看起来""
没有&#39 ; t count)然后在连接后将其删除?
答案 0 :(得分:3)
您可以迭代级别值并进行直接分配(一次一个值)
In [55]: df.columns.get_level_values(1)
Out[55]: Index([u'A', u'B'], dtype='object')
In [51]: df[('Half','A')] = df[('Val','A')]/2
In [52]: df[('Half','B')] = df[('Val','B')]/2
In [53]: df
Out[53]:
Val Half
A B A B
0 0 12 0.0 6.0
1 0 5 0.0 2.5
2 0 26 0.0 13.0
3 3 0 1.5 0.0
4 25 0 12.5 0.0
你也可以这样做
In [59]: concat([df['Val'],df['Val']/2],axis=1,keys=['Val','Half'])
Out[59]:
Val Half
A B A B
0 0 10 0.0 5.0
1 0 10 0.0 5.0
2 0 13 0.0 6.5
3 27 0 13.5 0.0
4 2 0 1.0 0.0
此问题是跟踪此错误/增强功能的问题:https://github.com/pydata/pandas/issues/7475
答案 1 :(得分:1)
我认为此选项比concat选项更可取,因为您不必冒错误地重新标记'Val'列。如果你不同意,请纠正我!
根据您的输入数据框:
In [3]: df
Out[3]:
Val
A B
0 26 0
1 10 0
2 18 0
3 0 18
4 2 0
值得考虑的第三个选择是:
In [4]: df[pd.MultiIndex.from_product([['Half']] + df.columns.levels[1:])] = df['Val'] / 2
In [5]: df
Out[5]:
Val Half
A B A B
0 26 0 13 0
1 10 0 5 0
2 18 0 9 0
3 0 18 0 9
4 2 0 1 0
这种方法也适用于任意嵌套的MultiIndex。 (我不知道是否可以使用MultiIndex的子列进行此分配。)
In [1]: df = pd.DataFrame({'Val': np.random.randint(5, 30, 12)}, index=pd.MultiIndex.from_product([['A', 'B','C'], ['a', 'b'], [0, 1]])).unstack().unstack()
In [2]: df
Out[2]:
Val
0 1
a b a b
A 6 10 11 7
B 16 8 23 15
C 29 17 11 18
In [3]: df[pd.MultiIndex.from_product([['Half']] + df.columns.levels[1:])] = df['Val'] / 2
In [4]: df
Out[4]:
Val Half
0 1 0 1
a b a b a b a b
A 6 10 11 7 3.0 5.0 5.5 3.5
B 16 8 23 15 8.0 4.0 11.5 7.5
C 29 17 11 18 14.5 8.5 5.5 9.0