【发布时间】:2012-10-08 15:18:50
【问题描述】:
我有一个结构如下的数据框:
First A B
Second bar baz foo bar baz foo
Third cat dog cat dog cat dog cat dog cat dog cat dog
0 3 8 7 7 4 7 5 3 2 2 6 2
1 8 6 5 7 8 7 1 8 6 0 3 9
2 9 2 2 9 7 3 1 8 4 1 0 8
3 3 6 0 6 3 2 2 6 2 4 6 9
4 7 6 4 3 1 5 0 4 8 4 8 1
所以有三个列级别。我想在第二级添加一个新列,其中每个第三级都执行计算,例如“new”=“foo”+“bar”。所以生成的数据框看起来像:
First A B
Second bar baz foo new bar baz foo new
Third cat dog cat dog cat dog cat dog cat dog cat dog cat dog cat dog
0 3 8 7 7 4 7 7 15 5 3 2 2 6 2 11 5
1 8 6 5 7 8 7 16 13 1 8 6 0 3 9 4 17
2 9 2 2 9 7 3 16 5 1 8 4 1 0 8 1 16
3 3 6 0 6 3 2 6 8 2 6 2 4 6 9 8 15
4 7 6 4 3 1 5 8 11 0 4 8 4 8 1 8 5
我找到了一种解决方法,列在这篇文章的末尾,但它根本不是“熊猫风格”,而且容易出错。组上的应用或转换功能似乎是正确的方法,但经过数小时的尝试,我仍然没有成功。我认为正确的方法应该是这样的:
def func(data):
fi = data.columns[0][0]
th = data.columns[0][2]
data[(fi,'new',th)] = data[(fi,'foo',th)] + data[(fi,'bar',th)]
print data
return data
print grouped.apply(func)
新列已正确添加到函数中,但未返回。如果“新”列已存在于 df 中,则使用与转换相同的函数将起作用,但是如何在“动态”或分组之前在特定级别添加新列?
生成示例df的代码是:
import pandas, itertools
first = ['A','B']
second = ['foo','bar','baz']
third = ['dog', 'cat']
tuples = []
for tup in itertools.product(first, second, third):
tuples.append(tup)
columns = pandas.MultiIndex.from_tuples(tuples, names=['First','Second','Third'])
data = np.random.randint(0,10,(5, 12))
df = pandas.DataFrame(data, columns=columns)
我的解决方法:
dfnew = None
grouped = df.groupby(by=None, level=[0,2], axis=1)
for name, group in grouped:
newparam = group.xs('foo', axis=1, level=1) + group.xs('bar', axis=1, level=1)
dftmp = group.join(pandas.DataFrame(np.array(newparam), columns=pandas.MultiIndex.from_tuples([(group.columns[0][0], 'new', group.columns[0][2])], names=['First','Second', 'Third'])))
if dfnew is None:
dfnew = dftmp
else:
dfnew = pandas.concat([dfnew, dftmp], axis=1)
print dfnew.sort_index(axis=1)
这可行,但为每个组创建一个新数据框并“手动”分配级别是一种非常糟糕的做法。
那么正确的方法是什么?我发现了几个处理类似问题的帖子,但所有这些都只有 1 级列,而这正是我正在努力解决的问题。
【问题讨论】:
-
根据分组值创建新列是转换的任务,但我不知道转换是否可以输出多个列。我会像你一样解决这个问题。顺便说一句,transform 还会为每个组创建一个新框架,并在最后将它们全部连接起来。
-
让应用/转换机制能够输出结构化值并将那些广播到列中(即,如果元组由应用函数生成,则组件进入单独的列而不是元组成为原子单个列中的元素)将是一个很棒的功能,即使它只是语法糖。可能使用另一个方法名称,以明确意图(applyfork 或类似的东西,或关键字 splitseq=True in apply)。