Получить индексный номер из мультииндексного фрейма данных в Python - PullRequest
0 голосов
/ 26 июня 2018

Кажется, есть много ответов о том, как получить последнее значение индекса из pandas dataframe, но что я пытаюсь получить номер позиции индекса для последней строки каждого индекса на уровне 0 в мультииндексном кадре данных. Я нашел способ использовать цикл, но фрейм данных состоит из миллионов строк, и этот цикл медленный. Я предполагаю, что есть более питонический способ сделать это.

Вот мини-пример df3. Я хочу получить список (или, возможно, массив) чисел в индексе для df >> последней строки, прежде чем она изменится на новую акцию. Столбец индекса - это результаты, которые я хочу. это индексная позиция от df

Stock   Date      Index 
AAPL    12/31/2004  
        1/3/2005    
        1/4/2005    
        1/5/2005    
        1/6/2005    
        1/7/2005    
        1/10/2005   3475
AMZN    12/31/2004  
        1/3/2005    
        1/4/2005    
        1/5/2005    
        1/6/2005    
        1/7/2005    
        1/10/2005   6951
BAC     12/31/2004  
        1/3/2005    
        1/4/2005    
        1/5/2005    
        1/6/2005    
        1/7/2005    
       1/10/2005    10427

Это код, который я использую, где df3 в кадре данных

test_index_list = []
for start_index in range(len(df3)-1):
    end_index = start_index + 1
    if df3.index[start_index][0] != df3.index[end_index][0]:
       test_index_list.append(start_index)

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

dict.values

Использование dict для отслеживания значений оставляет последнее найденное значение как значение, которое имеет значение.

list(dict(map(reversed, enumerate(df.index.get_level_values(0)))).values())

[2, 4, 5]

с петлей

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

def last(bins, k):
    a = np.zeros(k, np.int64)
    for i, b in enumerate(bins):
        a[b] = i
    return a

Затем вы можете получить факторизацию с помощью

f, u = pd.factorize(df.index.get_level_values(0))
last(f, len(u))

array([2, 4, 5])

Тем не менее, способ MultiIndex обычно строится, объекты labels уже являются факторизациями, а объекты levels - уникальными значениями.

last(df.index.labels[0], df.index.levels[0].size)

array([2, 4, 5])

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

from numba import njit

@njit
def nlast(bins, k):
    a = np.zeros(k, np.int64)
    for i, b in enumerate(bins):
        a[b] = i
    return a

nlast(df.index.labels[0], df.index.levels[0].size)

array([2, 4, 5])

Сроки

%%timeit
f, u = pd.factorize(df.index.get_level_values(0))
last(f, len(u))

641 µs ± 9.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%%timeit
f, u = pd.factorize(df.index.get_level_values(0))
nlast(f, len(u))

264 µs ± 11.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%%timeit
nlast(df.index.labels[0], len(df.index.levels[0]))

4.06 µs ± 43.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%%timeit
last(df.index.labels[0], len(df.index.levels[0]))

654 µs ± 14.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%%timeit
list(dict(map(reversed, enumerate(df.index.get_level_values(0)))).values())

709 µs ± 4.94 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

решение Джезраэля. Также очень быстро.

%timeit start_stop_arr(df.index.get_level_values(0))

113 µs ± 83.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

np.unique

Я не рассчитывал это, потому что мне это не нравится. Смотрите ниже:

Использование np.unique и аргумент return_index. Это возвращает первое место, где найдено каждое уникальное значение. После этого я бы сделал несколько сдвигов, чтобы получить последнюю позицию предыдущего уникального значения.

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

i = np.unique(df.index.get_level_values(0), return_index=True)[1]
np.append(i[1:], len(df)) - 1

array([2, 4, 5])

Настройка

из @ jezrael

df = pd.DataFrame({'A':list('abcdef'),
                   'B':[4,5,4,5,5,4],
                   'C':[7,8,9,4,2,3],
                   'D':[1,3,5,7,1,0],
                   'E':[5,3,6,9,2,4],
                   'F':list('aaabbc')}).set_index(['F','A','B'])
0 голосов
/ 26 июня 2018

Я изменяю ответ дивакара немного с get_level_values для индексов первого уровня MultiIndex:

df = pd.DataFrame({'A':list('abcdef'),
                   'B':[4,5,4,5,5,4],
                   'C':[7,8,9,4,2,3],
                   'D':[1,3,5,7,1,0],
                   'E':[5,3,6,9,2,4],
                   'F':list('aaabbc')}).set_index(['F','A','B'])

print (df)
       C  D  E
F A B         
a a 4  7  1  5
  b 5  8  3  3
  c 4  9  5  6
b d 5  4  7  9
  e 5  2  1  2
c f 4  3  0  4

def start_stop_arr(initial_list):
    a = np.asarray(initial_list)
    mask = np.concatenate(([True], a[1:] != a[:-1], [True]))
    idx = np.flatnonzero(mask)
    stop = idx[1:]-1
    return stop

print (df.index.get_level_values(0))
Index(['a', 'a', 'a', 'b', 'b', 'c'], dtype='object', name='F')

print (start_stop_arr(df.index.get_level_values(0)))
[2 4 5]
...