Отметить повторяющиеся записи во временном ряду pandas - PullRequest
4 голосов
/ 06 января 2020

У меня есть фрейм данных, который принимает эту форму (но имеет длину в несколько миллионов строк):

import pandas as pd     
dict = {'id':["A", "A", "A", "B", "B", "B", "C", "C", "C", "D", "D", "D"], 
    'year': ["2000", "2001", "2002", "2000", "2001", "2003", "1999", "2000", "2001", "2000", "2000", "2001"],
    'vacation':["France", "Morocco", "Morocco", "Germany", "Germany", "Germany", "Japan", "Australia", "Japan", "Canada", "Mexico", "China"],
    'new':[1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1]} 
df = pd.DataFrame(dict)

A   2000    France
A   2001    Morocco
A   2002    Morocco
B   2000    Germany
B   2001    Germany
B   2003    Germany
C   1999    Japan
C   2000    Australia
C   2001    Japan
D   2000    Canada       
D   2000    Mexico       
D   2001    China        

Для каждого человека в каждом году назначается (-ются) пункт (ы) отпуска; в данном году может быть несколько мест отдыха. Я хотел бы отметить строки, когда участник отправляется в отпуск в пункт назначения, куда он не ездил годом ранее (т. Е. Пункт назначения новый ). В приведенном выше случае выходные данные будут:

id  year    vacation    new
A   2000    France       1
A   2001    Morocco      1
A   2002    Morocco      0
B   2001    Germany      1
B   2002    Germany      0
B   2003    Germany      0
C   1999    Japan        1
C   1999    Australia    1
C   2000    Japan        1
D   2000    Canada       1
D   2000    Mexico       1
D   2001    China        1

Для A, B, C и D первый пункт назначения в нашем фрейме данных помечается как новый. Когда А едет в Марокко два года подряд, второе вхождение не помечается, потому что А ездил туда годом ранее. Когда B едет в Германию 3 раза подряд, 2-е и 3-е вхождения не помечаются. Когда человек C дважды ездит в Японию, все случаи помечаются, потому что они не go в Японию два года подряд . D отправляется в 3 разных пункта назначения (хотя и в 2 пункта назначения в 2000 году), и все они помечены.

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

Буду признателен за любой вклад; спасибо.

Ответы [ 3 ]

4 голосов
/ 06 января 2020

IIU C,

то, что мы делаем, группируем по id & vacation и гарантируем, что год не равен указанному выше, или мы можем выбрать первый экземпляр этой комбинации ,

надеюсь, это понятно. дайте мне знать, если вам нужна дополнительная помощь.

df["new_2"] = (
    df.groupby(["id", "vacation"])["id", "year"]
    .apply(lambda x: x.ne(x.shift()))
    .all(axis=1)
    .add(0)
)

print(df)
  id  year   vacation  new_2
0  A  2000     France    1
1  A  2001        USA    1
2  A  2002     France    0
3  B  2001    Germany    1
4  B  2002    Germany    0
5  B  2003    Germany    0
6  C  1999      Japan    1
7  C  2000  Australia    1
8  C  2001     France    1
2 голосов
/ 06 января 2020

Вот способ использования groupby+cumcount и series.mask:

df['new']=df.groupby(['id','vacation']).cumcount().add(1).mask(lambda x: x.gt(1),0)
print(df)

  id  year   vacation  new
0  A  2000     France    1
1  A  2001        USA    1
2  A  2002     France    0
3  B  2001    Germany    1
4  B  2002    Germany    0
5  B  2003    Germany    0
6  C  1999      Japan    1
7  C  2000  Australia    1
8  C  2001     France    1
2 голосов
/ 06 января 2020

Вот одно решение, которое я придумал, используя групповую обработку и преобразование:

df = df.sort_values(["id", "vacation", "year"])
df["new"] = (
    df.groupby(["id", "vacation"])
    .transform(lambda x: x.iloc[0])
    .year.eq(df.year)
    .astype(int)
)

Вы получите

  id  year   vacation  new
0  A  2000     France    1
1  A  2001        USA    1
2  A  2002     France    0
3  B  2001    Germany    1
4  B  2002    Germany    0
5  B  2003    Germany    0
6  C  1999      Japan    1
7  C  2000  Australia    1
8  C  2001     France    1
...