Python Pandas: как да добавите напълно нова колона към рамка с данни вътре в операция групиране/трансформиране

Искам да маркирам някои квантили в моите данни и за всеки ред от DataFrame бих искал записът в нова колона, наречена напр. "xtile", за да задържи тази стойност.

Да предположим например, че създавам рамка с данни като тази:

import pandas, numpy as np
dfrm = pandas.DataFrame({'A':np.random.rand(100), 
                         'B':(50+np.random.randn(100)), 
                         'C':np.random.randint(low=0, high=3, size=(100,))})

И да кажем, че напиша собствена функция за изчисляване на квинтила на всеки елемент в масив. Имам собствена функция за това, но например просто вижте scipy.stats.mstats.mquantile.

import scipy.stats as st
def mark_quintiles(x, breakpoints):
    # Assume this is filled in, using st.mstats.mquantiles.
    # This returns an array the same shape as x, with an integer for which
    # breakpoint-bucket that entry of x falls into.

Сега истинският въпрос е как да използвате transform за добавяне на нова колона към данните. Нещо като това:

def transformXtiles(dataFrame, inputColumnName, newColumnName, breaks):
    dataFrame[newColumnName] = mark_quintiles(dataFrame[inputColumnName].values, 
                                              breaks)
    return dataFrame

И тогава:

dfrm.groupby("C").transform(lambda x: transformXtiles(x, "A", "A_xtile", [0.2, 0.4, 0.6, 0.8, 1.0]))

Проблемът е, че горният код няма да добави новата колона "A_xtile". Той просто връща рамката ми с данни непроменена. Ако първо добавя колона, пълна с фиктивни стойности, като NaN, наречена „A_xtile“, тогава тя прави успешно презаписва тази колона, за да включи правилните маркировки на квинтила.

Но е изключително неудобно първо да пиша в колоната за нещо подобно, което може да искам да добавя в движение.

Обърнете внимание, че просто apply няма да работи тук, тъй като няма да знае как да осмисли евентуално различни по размер масиви с резултати за всяка група.


person ely    schedule 12.09.2012    source източник
comment
Не. Моля, вижте библиотеката на Pandas.   -  person ely    schedule 12.09.2012
comment
Това е невероятно същото като въпрос, който тъкмо щях да задам! Странно!   -  person smci    schedule 21.03.2013


Отговори (1)


Какви проблеми срещате с apply? Работи за този пример за играчка тук и дължините на групите са различни:

In [82]: df
Out[82]: 
   X         Y
0  0 -0.631214
1  0  0.783142
2  0  0.526045
3  1 -1.750058
4  1  1.163868
5  1  1.625538
6  1  0.076105
7  2  0.183492
8  2  0.541400
9  2 -0.672809

In [83]: def func(x):
   ....:     x['NewCol'] = np.nan
   ....:     return x
   ....: 

In [84]: df.groupby('X').apply(func)
Out[84]: 
   X         Y  NewCol
0  0 -0.631214     NaN
1  0  0.783142     NaN
2  0  0.526045     NaN
3  1 -1.750058     NaN
4  1  1.163868     NaN
5  1  1.625538     NaN
6  1  0.076105     NaN
7  2  0.183492     NaN
8  2  0.541400     NaN
9  2 -0.672809     NaN
person Chang She    schedule 12.09.2012
comment
Трябва да е достатъчно умен, за да знае къде автоматично да залепи специфичните за групата части от тази нова колона. По принцип синтаксисът df["NewCol"] = df.groupby("X").apply(some_inline_func) трябва да е аналогичен на същото като дефинирането на some_inline_func по начина, по който дефинирахте func по-горе. - person ely; 12.09.2012
comment
Какво ще кажете за: dfrm['A_xtile'] = dfrm.groupby('C').A.transform(mark_quintiles, [0.2, 0.4, 0.6, 0.8, 1.0])? (Изглежда, че работи на най-новата версия на pandas, не съм пробвал по-стари) - person Chang She; 13.09.2012
comment
Това е отлично и заслужава да бъде в пандас Split-Apply-Combine doc Току-що прекарах 4 дни, опитвайки се да изпробвам set_index, sort_index и т.н., за да вмъкна отново резултат от groupby обратно в неговия изходен кадър с данни. - person smci; 03.05.2013
comment
@ChangShe, когато опитам df.groupby('X').apply(func), получената рамка от данни вече се индексира от групиранията, които е извършила. Защо вашият не се държи така? - person guy; 20.07.2017
comment
@guy Добавете group_keys=False като аргумент в groupby - person cs95; 22.01.2019