2015-12-15 2 views
5

с учетом кадра данных с одним описательным столбцом и X числовыми столбцами, для каждой строки я хотел бы идентифицировать верхние N столбцов с более высокими значениями и сохранить их как строки на новый dataframe.Поиск верхних N столбцов для каждой строки в фрейме данных

Например, рассмотрим следующий кадр данных:

df = pd.DataFrame() 
df['index'] = ['A', 'B', 'C', 'D','E', 'F'] 
df['option1'] = [1,5,3,7,9,3] 
df['option2'] = [8,4,5,6,9,2] 
df['option3'] = [9,9,1,3,9,5] 
df['option4'] = [3,8,3,5,7,0] 
df['option5'] = [2,3,4,9,4,2] 

enter image description here

Я хотел бы выход (позволяет сказать, N 3, поэтому я хочу, топ-3):

A,option3 
A,option2 
A,option4 

B,option3 
B,option4 
B,option1 

C,option2 
C,option5 
C,option4 (or option1 - ties arent really a problem) 

D,option5 
D,option1 
D,option2 

and so on.... 

любая идея, как это легко достичь? Благодаря

+2

какой формат сделать вас хотеть? –

+0

Поскольку OP никогда не отвечал, давайте сделаем разумное предположение, что они хотят получить данные, а не список списков или что-то еще. – smci

+0

Переименовать, поскольку OP, по-видимому, хочет * «Найти верхние N столбцов» * вместо * «Выбор верхних N столбцов ...» *, который будет работать с pandas с выходом df. – smci

ответ

3

Если вы просто хотите спариваний:

from operator import itemgetter as it 
from itertools import repeat 
n = 3 

# sort_values = order pandas < 0.17 
new_d = (zip(repeat(row["index"]), map(it(0),(row[1:].sort_values(ascending=0)[:n].iteritems()))) 
       for _, row in df.iterrows()) 
for row in new_d: 
    print(list(row)) 

Выход:

[('B', 'option3'), ('B', 'option4'), ('B', 'option1')] 
[('C', 'option2'), ('C', 'option5'), ('C', 'option1')] 
[('D', 'option5'), ('D', 'option1'), ('D', 'option2')] 
[('E', 'option1'), ('E', 'option2'), ('E', 'option3')] 
[('F', 'option3'), ('F', 'option1'), ('F', 'option2')] 

Который также поддерживает порядок.

Если вы хотите получить список списков:

from operator import itemgetter as it 
from itertools import repeat 
n = 3 

new_d = [list(zip(repeat(row["index"]), map(it(0),(row[1:].sort_values(ascending=0)[:n].iteritems())))) 
       for _, row in df.iterrows()] 

Выходные:

[[('A', 'option3'), ('A', 'option2'), ('A', 'option4')], 
[('B', 'option3'), ('B', 'option4'), ('B', 'option1')], 
[('C', 'option2'), ('C', 'option5'), ('C', 'option1')], 
[('D', 'option5'), ('D', 'option1'), ('D', 'option2')], 
[('E', 'option1'), ('E', 'option2'), ('E', 'option3')], 
[('F', 'option3'), ('F', 'option1'), ('F', 'option2')]] 

Или с помощью питоны отсортированный:

new_d = [list(zip(repeat(row["index"]), map(it(0), sorted(row[1:].iteritems(), key=it(1) ,reverse=1)[:n]))) 
        for _, row in df.iterrows()] 

Что на самом деле самый быстрый, если вы действительно хотите Строки, довольно тривиально форматировать вывод, как вы хотите.

+0

Это дает значения, а не имена колонок. – iled

+0

@lied, OP может или не хочет имена, это тривиально изменить, если они это сделают, я спросил в комментарии, чтобы уточнить –

+0

спасибо Padraic, у меня есть пример желаемого вывода на вопрос. Тем не менее, любая идея, почему ваш код дает мне эту ошибку: AttributeError: объект «Series» не имеет атрибутов «items» n «pd.DataFrame (map (it (0), отсортировано (строка [1:]. Items(), key = it (1), reverse = 1) [: n]) для строки _, строка в df.iterrows())? – Diego

1
dfc = df.copy() 
result = {} 

#First, I would effectively transpose this 

for key in dfc: 
    if key != 'index': 
     for i in xrange(0,len(dfc['index'])): 
      if dfc['index'][i] not in result: 
       result[dfc['index'][i]] = [] 
      result[dfc['index'][i]] += [(key,dfc[key][i])] 


def get_topn(result,n): 
    #Use this to get the top value for each option 
    return [x[0] for x in sorted(result,key=lambda x:-x[1])[0:min(len(result),n)]] 


#Lastly, print the output in your desired format. 
n = 3 
keys = sorted([k for k in result]) 
for key in keys: 
     for option in get_topn(result[key],n): 
     print str(key) + ',' + str(option) 
     print 
+0

спасибо Адаму, что было действительно полезно, единственная проблема заключалась в том, что порядок идентификаторов в конце концов изменился из-за преобразования словаря. Я решил это, сортируя «ключи», используя исходный фрейм. Маленький хак, но это нормально – Diego

2

Предположим

N = 3 

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

matrix = [[(j, 'option' + str(i)) for j in df['option' + str(i)]] for i in range(1,6)] 

Результат этой линии будет:

[ 
[(1, 'option1'), (5, 'option1'), (3, 'option1'), (7, 'option1'), (9, 'option1'), (3, 'option1')], 
[(8, 'option2'), (4, 'option2'), (5, 'option2'), (6, 'option2'), (9, 'option2'), (2, 'option2')], 
[(9, 'option3'), (9, 'option3'), (1, 'option3'), (3, 'option3'), (9, 'option3'), (5, 'option3')], 
[(3, 'option4'), (8, 'option4'), (3, 'option4'), (5, 'option4'), (7, 'option4'), (0, 'option4')], 
[(2, 'option5'), (3, 'option5'), (4, 'option5'), (9, 'option5'), (4, 'option5'), (2, 'option5')] 
] 

Тогда мы можем Исли преобразование матрицы с использованием функции почтового индекса, сортировать результат строк по первому элементу кортежа и принять N первых элементов:

transformed = [sorted(l, key=lambda x: x[0], reverse=True)[:N] for l in zip(*matrix)] 

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

[ 
[(9, 'option3'), (8, 'option2'), (3, 'option4')], 
[(9, 'option3'), (8, 'option4'), (5, 'option1')], 
[(5, 'option2'), (4, 'option5'), (3, 'option1')], 
[(9, 'option5'), (7, 'option1'), (6, 'option2')], 
[(9, 'option1'), (9, 'option2'), (9, 'option3')], 
[(5, 'option3'), (3, 'option1'), (2, 'option2')] 
] 

Последний шаг будет присоединяться индекс столбца и результат кортежа по:

for id, top in zip(df['index'], transformed): 
    for option in top: 
     print id + ',' + option[1] 
    print '' 
+0

Это выглядит хорошим ответом! –

+0

Это интересное решение, но оно зависит от предопределенных имен столбцов. Я использовал опцию 1, вариант2, ... простоту, имена не следуют логике и могут быть разными в зависимости от ситуации. Но спасибо за помощь – Diego

0

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

n = 3 
df.index = pd.Index(df['index']) 
del df['index'] 
df = df.transpose().unstack() 
for i, g in df.groupby(level=0): 
    g = g.sort_values(ascending=False) 
    print i, list(g.index.get_level_values(1)[:n]) 
+1

Это изменяет исходный фрейм данных, I я не уверен, что это то, что хочет OP –

0

еще один сумасшедший Однострочник, учитывая n = 3

{index:option for (index, option) in zip(df['index'], 
    [df.columns[pd.notnull(x[1].where(x[1][1:].sort_values()[-n:]))].tolist() 
     for x in df.iterrows()])} 

{'A': ['option2', 'option3', 'option4'], 
'C': ['option2', 'option4', 'option5'], 
'B': ['option1', 'option3', 'option4'], 
'E': ['option1', 'option2', 'option3'], 
'D': ['option1', 'option2', 'option5'], 
'F': ['option1', 'option3', 'option5']} 

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

  • Нет связанных вопросов^_^