Панды: вернуть значения индекса для первого и последнего экземпляра значения - PullRequest
0 голосов
/ 24 мая 2018

У меня есть следующий DataFrame:

df = pd.DataFrame({'index':[0,1,2,3,4,5,6,7,8,9,10], 'X':[0,0,1,1,0,0,1,1,1,0,0]})
df.set_index('index', inplace = True)

   X
index   
0      0
1      0
2      1
3      1
4      0
5      0
6      1
7      1
8      1
9      0
10     0

Мне нужно вернуть список кортежей, показывающий значение индекса для первого и последнего экземпляров 1 для каждой последовательности 1 (извините, если этозапутанный).т.е.

Want:

[(2,3), (6,8)]

Первый экземпляр первого 1 происходит в точке индекса 2, затем последний 1 в этой последовательности встречается в точке индекса 3. Следующий 1 встречается в индексеточка 6, а последняя 1 в этой последовательности встречается в точке индекса 8.

То, что я пробовал:

Я могу получить первый, используя функцию argmax numpy.то есть

x1 = np.argmax(df.values)
y1 = np.argmin(df.values[x1:])
(x1,2 + y1 - 1)

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

Ответы [ 3 ]

0 голосов
/ 24 мая 2018

Вы можете использовать стороннюю библиотеку: more_itertools

loc с mit.consecutive_groups

[list(group) for group in mit.consecutive_groups(df.loc[df.ones == 1].index)]

# [[2, 3], [6, 7, 8]]

Простое понимание списка:

x = [(i[0], i[-1]) for i in x]

#  [(2, 3), (6, 8)]

Подход с использованием numpy, адаптированный из отличный ответ @Warren Weckesser

def runs(a):
    isone = np.concatenate(([0], np.equal(a, 1).view(np.int8), [0]))
    absdiff = np.abs(np.diff(isone))
    ranges = np.where(absdiff == 1)[0].reshape(-1, 2)
    return [(i, j-1) for i, j in ranges]

runs(df.ones.values)
# [(2, 3), (6, 8)]
0 голосов
/ 25 мая 2018

Вот чистое решение для панд:

df.groupby(df['X'].eq(0).cumsum().mask(df['X'].eq(0)))\
  .apply(lambda x: (x.first_valid_index(),x.last_valid_index()))\
  .tolist()

Вывод:

[(2, 3), (6, 8)]
0 голосов
/ 24 мая 2018

Вам нужно more_itertools.consecutive_groups

import more_itertools as mit
def find_ranges(iterable):
    """Yield range of consecutive numbers."""
    for group in mit.consecutive_groups(iterable):
        group = list(group)
        if len(group) == 1:
            yield group[0]
        else:
            yield group[0], group[-1]
list(find_ranges(df['X'][df['X']==1].index))

Вывод:

[(2, 3), (6, 8)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...