2015-01-25 2 views
1

У меня есть панда DataFrame с большим количеством строк. Я пытаюсь создать новые столбцы для фрейма на основе внутригруппового ранжирования членов. Вот некоторые поддельные данные, иллюстрирующее то, что у меня есть:Использование pandas для создания новых столбцов на основе внутригруппового ранжирования

Num_members = int(1.e7) 
Num_groups = int(1.e5) 
members = pd.DataFrame({ 
    'ID': np.arange(Num_members), 
    'groupID': np.random.random_integers(0, 2*Num_groups, Num_members), 
    'groupmass': np.zeros(Num_members), 
    'brightness': np.random.uniform(8,12, Num_members), 
    'color':np.random.uniform(0,1,Num_members) 
}) 

Я пытаюсь создать две новые колонки для членов:

  • Внутриорганизационной группа ранга порядка для яркости, так что яркая член группы получит значение , следующий по яркости и т.д.

  • Цвет самого яркого члена группы. Таким образом, для этого столбца всем членам той же группы присваивается то же значение, что и «цвет» элемента с внутригрупповой яркостью-ранг = 0.

Я знаю, что операция GroupBy предназначена именно для такого рода манипуляций, но я не мог понять, как сделать это правильно. И скорость - важная проблема, поскольку мой набор данных большой, и мне нужно сделать это в анализе вероятности MCMC.

ответ

2

Я дам ему еще одну попытку:

import pandas as pd 
import numpy as np 
np.random.seed(42) 
Num_members = int(10) 
Num_groups = int(1) 
members = pd.DataFrame({ 
    'ID': np.arange(Num_members), 
    'groupID': np.random.random_integers(0, 2*Num_groups, Num_members), 
    'groupmass': np.zeros(Num_members), 
    'brightness': np.random.uniform(8,12, Num_members), 
    'color':np.random.uniform(0,1,Num_members) 
}) 

И логика:

df = members.groupby("groupID").agg({"brightness": np.max}) 
df = df.reset_index() 
df = df.merge(members[["groupID", "brightness", "color"]], on=("groupID", "brightness")) 

Сначала мы делаем группировку, чтобы найти максимальное значение brightness. После этого мы объединяем df с members, чтобы получить значение color элемента с самыми высокими значениями brightness. В основном мы объединяем все строки в members и df, которые имеют те же значения brightness и groupID.

Обратите внимание, что это может привести к неожиданному дублированию строк, если в группе имеется несколько значений с максимальным количеством баллов.

df теперь выглядит следующим образом:

groupID brightness color 
0 0 11.879639 0.139494 
1 1 8.849356 0.366362 
2 2 11.329771 0.292145 

Для каждой группы он содержит groupID, максимальное значение brightness и color элемента с максимальным значением яркости.

Теперь мы можем объединить кадры данных members и df:

result = members.merge(df, on="groupID", suffixes=("_member", "_group")) 

И получите следующий результат:

ID brightness_member color_member groupID groupmass brightness_group color_group 
0 0 8.232334 0.304242 2 0 11.329771 0.292145 
1 2 10.404460 0.431945 2 0 11.329771 0.292145 
2 3 10.832290 0.291229 2 0 11.329771 0.292145 
3 6 11.329771 0.292145 2 0 11.329771 0.292145 
4 8 8.727300 0.456070 2 0 11.329771 0.292145 
5 9 8.733618 0.785176 2 0 11.329771 0.292145 
6 1 11.464705 0.524756 0 0 11.879639 0.139494 
7 4 8.082338 0.611853 0 0 11.879639 0.139494 
8 5 11.879639 0.139494 0 0 11.879639 0.139494 
9 7 8.849356 0.366362 1 0 8.849356 0.366362 
+0

Это действительно * много * быстрее, cel. Это определенно решает проблему «найти самый яркий член каждой группы». Это не совсем то, что я искал, что «находило * цвет» самого яркого члена группы, но все равно это все еще очень полезно. Я бы с радостью поддержал, если бы вы не возражали, просто кратко объясняя логику этот синтаксис, который немного сложнее, чем ваше первое решение. (Аналогично, я бы с радостью предоставил дополнительную информацию о цветовом вопросе, но вы уже были очень полезны, как есть). – aph

+0

@aph, и есть еще одно обновление ... он становится все сложнее, я думаю ...: D – cel

+2

Я думаю, что использовать «трансформировать» чище, но, к сожалению, мои тесты показывают, что он медленнее.: -/Я думаю, основная проблема заключается в том, что баланс Python против Cython в кодовой базе оптимизирован для нескольких групп с большим количеством участников, а не с множеством групп. – DSM

2

Это моя игрушка пример:

import pandas as pd 
import numpy as np 
numpy.random.seed(42) 
Num_members = int(10) 
Num_groups = int(1) 
members = pd.DataFrame({ 
    'ID': np.arange(Num_members), 
    'groupID': np.random.random_integers(0, 2*Num_groups, Num_members), 
    'groupmass': np.zeros(Num_members), 
    'brightness': np.random.uniform(8,12, Num_members), 
    'color':np.random.uniform(0,1,Num_members) 
}) 

С пользовательской функции, которая вычисляет ранг и максимальное значение яркости:

def rank_max_fun(df): 
    df["b_rank"] = df.brightness.rank(ascending=False) 
    df["b_max"] = df.brightness.max() 
    return df 

Группировка и применение

df = members.groupby("groupID", sort=False).apply(rank_max_fun) 

урожаи :

ID brightness color groupID groupmass b_rank b_max 
0 0 8.232334 0.304242 2 0 6 11.329771 
1 1 11.464705 0.524756 0 0 2 11.879639 
2 2 10.404460 0.431945 2 0 3 11.329771 
3 3 10.832290 0.291229 2 0 2 11.329771 
4 4 8.082338 0.611853 0 0 3 11.879639 
5 5 11.879639 0.139494 0 0 1 11.879639 
6 6 11.329771 0.292145 2 0 1 11.329771 
7 7 8.849356 0.366362 1 0 1 8.849356 
8 8 8.727300 0.456070 2 0 5 11.329771 
9 9 8.733618 0.785176 2 0 4 11.329771 

Даунсайд: для больших наборов данных требуется довольно много времени.

+0

элегантное решение; это очень естественно. Ваше решение также прекрасно масштабируется до 1e6 членов, но вы правы, что это медленно: 20s время исполнения, когда я наращиваю Num_members & Num_groups. Может быть, операция, которую я требую, является просто дорогостоящей из-за внутригрупповой сортировки. Хотя циклы FOR, которые я написал в прямом C, чтобы выполнить одну и ту же задачу, примерно в 10 раз быстрее, чем это, поэтому я не уверен, что является основной причиной повышения производительности. – aph

+0

Итак, одна мысль по этим линиям состоит в том, что я, вероятно, обойдусь без рейтинга каждого члена. Все, что мне действительно нужно знать, является ли каждый из участников самым ярким или не ярким. Таким образом .idxmax может быть намного быстрее, чем полный класс ранга. Знаете, как я буду использовать idxmax плюс пользовательскую функцию для второго столбца, о котором я спрашивал, - цвет самого яркого члена группы? – aph

Смежные вопросы