Как использовать цепочку методов Pandas .assign() в столбце MultiIndex?
Для индексированного столбца одного уровня я бы сделал следующее
arrays = [['one', 'two', ]]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df = pd.DataFrame(pd.np.random.randn(3, 2), index=['A', 'B', 'C'], columns=index)
print(df)
first one two
A 0.919921 -1.407321
B 1.100169 -0.927249
C -0.520308 0.619783
print(df.assign(one=lambda x: x.one * 100))
first one two
A 144.950877 0.633516
B -0.593133 -0.630641
C -5.661949 -0.738884
Теперь, когда у меня есть столбец MultiIndex, я могу получить доступ к нужному столбцу, используя .loc
но я не могу присвоить это чему-либо, так как это приводит к ошибке SyntaxError: keyword can't be an expression
,
Вот пример,
arrays = [['bar', 'bar'],
['one', 'two']]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df = pd.DataFrame(pd.np.random.randn(3, 2), index=['A', 'B', 'C'], columns=index)
print(df)
first bar
second one two
A 1.119243 0.819455
B -0.473354 -1.340502
C 0.150403 -0.211392
Тем не мение,
df.assign(('bar', 'one')=lambda x: x.loc[:, ('bar', 'one')] * 10)
SyntaxError: keyword can't be an expression
я могу сделать
df.assign(barOne=lambda x: x.loc[:, ('bar', 'one')] * 10)
first bar barOne
second one two
A 0.433909 0.949701 4.339091
B 0.011486 -1.395144 0.114858
C -0.289821 2.106951 -2.89821
но это не желательно. Я хотел бы сохранить цепочку моих методов, но также сохранить столбец MultiIndexed.
4 ответа
Просто для того, чтобы получить больше информации в одном месте - вот этот вопрос (поднятый вами) на GitHub, и ответ был:
Вы можете просто напрямую индексировать
df[('a', 1)] = ...
.assign
не может поддерживать этот синтаксис как вызов функции, где кортеж не является допустимым идентификатором.
Если я правильно читаю, разве это не так просто, как:
Оригинал df:
first bar
second one two
A 0.386729 1.014010
B 0.236824 0.439019
C 0.530020 -0.268751
Код:
df[('bar','one')] *= 10
Обновлен df (изменить столбец):
first bar
second one two
A 3.8672946 1.014010
B 2.3682376 0.439019
C 5.3002040 -0.268751
Или обновил df (создайте новый столбец):
df[('bar','new')] = df[('bar','one')] * 10
first bar
second one two new
A 0.386729 1.014010 3.867295
B 0.236824 0.439019 2.368238
C 0.530020 -0.268751 5.300204
Этот обходной путь, использующий цепочку методов, даст вам желаемый результат.
df = (df.assign(barOne=lambda x: x.loc[:, ('bar', 'one')]*10)
.rename(columns={'':'barOne'}, level=1)
.rename(columns={'barOne':'bar'}, level=0)
)
df
first bar
second one two barOne
A -0.016595 0.613149 -0.165947
B -1.108934 -2.662668 -11.089339
C 0.022323 1.749033 0.223232
df.columns
MultiIndex([('bar', 'one'),
('bar', 'two'),
('bar', 'barOne')],
names=['first', 'second'])
С использованием
.join()
(аLEFT JOIN
):
df.drop(columns=('bar', 'one')).join(df[('bar', 'one')] * 10)
Результат:
first bar
second two one
A 0.949701 4.339091
B -1.395144 0.114858
C 2.106951 -2.89821
Еслиdf
еще не назначено, цепочку можно сделать возможной с помощью
.pipe()
слишком:
(...).pipe(
lambda df: df.drop(columns=('bar', 'one')).join(df[('bar', 'one')] * 10)
)
Такой же результат можно получить и с помощью
.append()
:
df.T.drop(('bar', 'one')).append(df[('bar', 'one')] * 10).T
но он устарел с версии 1.4.0 в пользу
pd.concat()
(анOUTER JOIN
):
pd.concat(axis='columns', objs=[
df.drop(columns=[('bar', 'one')]), df[('bar', 'one')] * 10,
])
И в любом случае можно быть полностью
.rename()
Столбцы MultiIndex в процессе:
(df[('bar', 'one')] * 10).rename(('baz', 'ten'))