我有以下数据框:
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
'C' : np.random.randn(8),
'D' : np.random.randn(8)})
A B C D
0 foo one 0.478183 -1.267588
1 bar one 0.555985 -2.143590
2 foo two -1.592865 1.251546
3 bar three 0.174138 -0.708198
4 foo two 0.302215 -0.219041
5 bar two -0.034550 -0.965414
6 foo one 1.310828 -0.388601
7 foo three 0.357659 -1.610443
我正在尝试添加另一个列,该列将是 C 列的标准化版本,而不是A:
normed = df.groupby('A').apply(lambda x: (x['C']-min(x['C']))/(max(x['C'])-min(x['C'])))
A
bar 1 0.000000
3 0.033396
5 1.000000
foo 0 1.000000
2 0.413716
4 0.000000
6 0.441061
7 0.357787
最后我想把这个结果加回到df(使用来自similar question的建议):
df.join(normed, on='A', rsuffix='_normed')
然而,我收到错误:
ValueError:len(left_on)必须等于索引中的级别数 “正确的”
如何将normed
结果添加回数据框df
?
答案 0 :(得分:3)
您收到此错误是因为您在第一级中有MultiIndex长度为2的情况。第二级是原始索引。
normed.index
Out[35]:
MultiIndex(levels=[['bar', 'foo'], [0, 1, 2, 3, 4, 5, 6, 7]],
labels=[[0, 0, 0, 1, 1, 1, 1, 1], [1, 3, 5, 0, 2, 4, 6, 7]],
names=['A', None])
您可能希望加入原始索引,因此必须删除新索引的第一级
normed.index = normed.index.droplevel()
加入之前:
df.join(normed, rsuffix='_normed')
答案 1 :(得分:2)
最简单的方法是将reset_index
应用于normed
normed = df.groupby('A').apply(lambda x: (x['C']-min(x['C']))/(max(x['C'])-min(x['C'])))
normed = normed.reset_index(level=0, drop=True)
现在只需将normed
添加为df
df['normed'] = normed
答案 2 :(得分:2)
实际上,有一个非常简单的解决方案。当groupby正在进行一对一操作(而不是减少)时,您可以使用transform
并且已经为您处理了索引:
df['c_normed'] = df.groupby('A')['C'].transform( lambda x: (x-min(x))/(max(x)-min(x)))
另请注意,如果您使用df.groupby('A')['C']
,代码会更清晰,因为您可以在lambda中使用x
而不是x['C']
。而且在这种情况下使用x['C']
使用apply但不使用transform(我不知道为什么......)。
答案 3 :(得分:1)
您可以做的是:
# Get tuples (index, value) for each level
foo = zip(normed.foo.index, normed.foo.values)
bar = zip(normed.bar.index, normed.bar.values)
# Merge the two lists
foo.extend(bar) # merged lists contained in foo
# Sort the list
new_list = sorted(foo, key=lambda x: x[0])
# Create new column in dataframe
index, values = zip(*new_list) # unzip
df['New_column'] = values
<强>输出强>
Out[85]:
A B C D New_column
0 foo one 0.039683 -0.041559 0.638594
1 bar one -0.090650 -2.316097 0.000000
2 foo two 0.024210 0.616764 0.629815
3 bar three 0.142740 0.156198 0.450339
4 foo two -1.085916 -0.432832 0.000000
5 bar two 0.427604 -1.154850 1.000000
6 foo one -0.156424 0.037188 0.527335
7 foo three 0.676706 -1.336921 1.000000
注意:也许有一种更聪明的方法可以做到这一点。
答案 4 :(得分:1)
你必须首先摆脱groupby创建的多索引的第一级(即'Foo'和'Bar')。
添加以下代码应该有效:
normed = normed.reset_index(level=0)
del normed['A']
normed.rename(columns={'C':'C_normed'}, inplace=True)
pd.concat([df, normed], axis=1)
结果:
A B C D C_normed
0 foo one 1.697923 0.656727 1.000000
1 bar one -0.626052 -0.466088 0.000000
2 foo two -0.501440 1.080408 0.000000
3 bar three 0.731791 -1.531915 1.000000
4 foo two -0.202666 0.275042 0.135846
5 bar two -0.340455 -0.737039 0.210332
6 foo one 0.506664 1.049853 0.458362
7 foo three -0.358317 -0.598262 0.065075