1
votes

Comment filtrer certaines valeurs sur des mois consécutifs?

J'ai un dataframe structuré comme suit:

Name    Month Grade

Sue     Jan   D

Sue     Feb   D

Jason   Mar   B

Sue     Mar   D

Jason   Jan   B

Sue     Apr   A

Jason   Feb   C

Je veux obtenir la liste des étudiants qui ont obtenu D 3 mois consécutifs au cours des 6 derniers mois. Dans l'exemple ci-dessus, Sue sera sur la liste depuis qu'elle a obtenu D en janvier, février et mars. Comment puis-je faire cela en utilisant Python ou Pandas ou Numpy?


9 commentaires

Les données sont-elles triées temporairement?


Avez-vous supposé qu'il y avait la même année?


@mephisto Non. Tant qu'il est consécutif, il peut s'agir d'années différentes. Par exemple, Jason devrait être sur la liste s'il a obtenu D en novembre 2018, décembre 2018 et janvier 2019.


votre mois est-il exactement tel qu'il est ici ou une date appropriée? comme le 15 janvier 2018 ou le 15/1/2019


@ansev Qu'entendez-vous par temporairement? Autant que je sache, il n'y a pas de tri spécial sur les données.


La colonne de date @Datanovice est telle qu'elle est présentée ici.


L'ordre des données d'entrée implique-t-il l'ordre du mois? Par exemple, si j'ai la note de Sue avec janvier, février, ..., décembre en 2018 et janvier, février en 2019, le deuxième Sue Jan implique-t-il toujours l'année suivante?


@Shenan Je filtre depuis 6 mois dans l'ensemble de données. Il n'y aura donc pas de valeurs de 2 janvier. Cependant, il peut y avoir des valeurs du 18 novembre, du 18 décembre et du 19 janvier. Par exemple, Jason devrait être sur la liste s'il obtient D en novembre 2018, décembre 2018 et janvier 2019


@Eenes check solution, cela devrait gérer les données sur plusieurs années.


3 Réponses :


0
votes

J'ai essayé de résoudre votre problème. J'ai une solution pour vous mais ce n'est peut-être pas la plus rapide en termes d'efficacité / exécution de code. Veuillez voir ci-dessous:

newdf[newdf['concatenated'].str.contains('DDD', regex=False, na=False)].index.to_list()

La sortie sera comme:

Month Jan Feb Mar Apr concatenated
Name                              
Sue     D   D   D   A         DDDA

Si vous voulez juste les noms, alors la commande suivante à la place. p>

newdf = df.pivot(index='Name', columns='Month', values='Grade')
newdf = newdf[['Jan', 'Feb', 'Mar', 'Apr']].fillna(-1)
newdf['concatenated'] = newdf['Jan'].astype('str') + newdf['Feb'].astype('str') + newdf['Mar'].astype('str') + newdf['Apr'].astype('str')
newdf[newdf['concatenated'].str.contains('DDD', regex=False, na=False)]


1 commentaires

Approche intéressante, cela fonctionne définitivement et ouvre même des perspectives plus intéressantes. Le dernier morceau de code ne fonctionnait cependant pas lorsque vous filtrez le DDD dans la colonne concaténée. Au lieu de cela, je reset_index et filtre la colonne.



0
votes

vous avez plusieurs façons de gérer cela, utilisez d'abord ma solution précédente, mais cela nécessitera de mapper les nombres académiques sur les mois (par exemple, septembre = 1, août = 12) de cette façon, vous pouvez appliquer les mathématiques pour calculer des valeurs consécutives. p> ce qui suit consiste à convertir le mois en date-heure et à calculer la différence en mois, nous pouvons ensuite appliquer une somme cumulative et filtrer toutes les valeurs supérieures à 3.

print(df.loc[df['Name'] == 'Sue'])
  Name Month Grade      date   count
3  Sue   Dec     D 1899-12-01      1
0  Sue   Jan     D 1900-01-01      2
1  Sue   Feb     D 1900-02-01      3
5  Sue   Apr     A 1900-04-01      1

print(df.drop('date',axis=1))
    Name Month Grade  count
4  Jason   Jan     B      1
6  Jason   Feb     C      1
2  Jason   Mar     B      1
3    Sue   Dec     D      1
0    Sue   Jan     D      2
1    Sue   Feb     D      3
5    Sue   Apr     A      1

d = StringIO("""Name    Month Grade
Sue     Jan   D
Sue     Feb   D
Jason   Mar   B
Sue     Dec   D 
Jason   Jan   B
Sue     Apr   A
Jason   Feb   C""")

df = pd.read_csv(d,sep='\s+')
df['date'] = pd.to_datetime(df['Month'],format='%b').dt.normalize()

# set any values greater than June to the previous year.
df['date'] = np.where(df['date'].dt.month > 6,
 (df['date'] - pd.DateOffset(years=1)),df['date']) 

df.sort_values(['Name','date'],inplace=True)

def month_diff(date):
    cumlative_months = (
        np.round(((date.sub(date.shift(1)) / np.timedelta64(1, "M")))).eq(1).cumsum() 
    ) + 1
return cumlative_months

df['count'] = df.groupby(["Name", "Grade"])["date"].apply(month_diff)


0 commentaires

0
votes

J'ai trouvé ceci.

['Sue']

Résultat:

df['Month_Nr'] = pd.to_datetime(df.Month, format='%b').dt.month

names  = df.Name.unique()
students = np.array([])

for name in names:
    filter = df[(df.Name==name) & (df.Grade=='D')].sort_values('Month_Nr')
    if filter['Month_Nr'].diff().cumsum().max() >= 2:
        students = np.append(students, name)

print(students)


0 commentaires