2
votes

Comment filtrer les valeurs de la série Pandas en fonction d'une condition

J'ai une série de pandas comme pd.Series ([- 1, -1, -1, 0, 0, 0, -5, -5, 0, 0, 0, -1, -1, -1, -1]) . Comment puis-je le convertir en pd.Series ([- 1, 0, 0, 0, -5, -5, 0, 0, 0, -1]) .

La condition à filtrer est que si les -1 sont supérieurs ou égaux à 3 dans une séquence, alors gardez la première occurrence et supprimez le reste.

Puisque la première séquence de -1 est 3 , nous gardons -1 et supprimons le reste. Après les premières valeurs 3 , la séquence se brise (puisque la valeur est maintenant 0 ). De même, la dernière séquence de -1 est 4 , donc nous gardons le -1 et supprimons le reste.

Le filtre s'applique uniquement à -1 et -5 doit être laissé tel quel

Merci

PS: J'ai pensé à groupby, mais je pense que cela ne respecte pas la séquence que j'ai décrite ci-dessus


4 commentaires

si -1s est supérieur à 3 dans une séquence - vous voulez dire plus de 2 ?


Désolé pour la confusion. Il aurait dû être supérieur ou égal à 3. Ajout de la modification à la question. Merci de l'avoir signalé


L'une des solutions affichées a-t-elle fonctionné pour vous?


Merci pour votre réponse Divakar. Je n'ai pas pu commenter plus tôt. Pardon


4 Réponses :


1
votes

IIUC, masquage des pandas et groupby:

>>> remove_streaks(4)
[-1, -1, -1, 0, 0, 0, -5, -5, 0, 0, 0, -1]

>>> remove_streaks(3)
[-1, 0, 0, 0, -5, -5, 0, 0, 0, -1]

def remove_streaks(T):
  '''T is the threshold
  '''

  g = s.groupby(s.diff().ne(0).cumsum() + s.ne(-1).cumsum())
  mask = g.transform('size').lt(T).cumsum() + s.diff().ne(0).cumsum() 

  return s.groupby(mask).first()


0 commentaires

2
votes

Avec masque conditionnel :

In [43]: s = pd.Series([-1, -1, -1, 0, 0, 0, -5, -5, 0, 0, 0, -1, -1, -1 , -1])                                         

In [44]: m = (s.diff() == 0) & (s.eq(-1))                                                                               

In [45]: s[~m]                                                                                                          
Out[45]: 
0    -1
3     0
4     0
5     0
6    -5
7    -5
8     0
9     0
10    0
11   -1
dtype: int64


1 commentaires

Cela supprime les stries de 2. Il ne devrait y en avoir que 3 ou plus.



2
votes

Avec certains outils SciPy -

# Using .tolist() simply for better visualization
In [47]: s.tolist()
Out[47]: [-1, -1, -1, 0, 0, 0, -5, -5, 0, 0, 0, -1, -1, -1, -1]

In [48]: keep_first_neg1s(s,W=3).tolist()
Out[48]: [-1, 0, 0, 0, -5, -5, 0, 0, 0, -1]

In [49]: keep_first_neg1s(s,W=4).tolist()
Out[49]: [-1, -1, -1, 0, 0, 0, -5, -5, 0, 0, 0, -1]

Un plus simple et, espérons-le, plus performant aussi -

def keep_first_neg1s_v2(s, W=3):
    m1 = binary_opening(a==-1, np.ones(W,dtype=bool))
    return s[np.r_[True,~m1[:-1]]]

S'exécute sur un échantillon donné s -

from scipy.ndimage.morphology import binary_opening,binary_erosion

def keep_first_neg1s(s, W=3):
    k1 = np.ones(W,dtype=bool)
    k2 = np.ones(2,dtype=bool)
    m = s==-1
    return s[~binary_erosion(binary_opening(m,k1),k2) | ~m]


0 commentaires

0
votes

Créez un masque booléen m pour identifier les positions où les valeurs changent. Groupby s sur m.cumsum () avec transformation pour identifier les groupes ayant un numéro de -1 m1 . Booléen m ou m1 et cumsum pour séparer uniquement les groupes avec numéro -1 > = 3 dans le même nombre. Enfin, utilisez dupliqué pour découper.

s
Out[148]:
0    -1
1    -1
2    -1
3     0
4    -1
5    -1
6     0
7     0
8    -5
9    -5
10    0
11    0
12    0
13   -1
14   -1
15   -1
16   -1
dtype: int64

m = s.diff().ne(0)

Out[150]:
0      True
1     False
2     False
3      True
4      True
5     False
6      True
7     False
8      True
9     False
10     True
11    False
12    False
13     True
14    False
15    False
16    False
dtype: bool

m1 = s.groupby(m.cumsum()).transform(lambda x: x.eq(-1).sum() < 3)

Out[152]:
0     False
1     False
2     False
3      True
4      True
5      True
6      True
7      True
8      True
9      True
10     True
11     True
12     True
13    False
14    False
15    False
16    False
dtype: bool

m2 = ~((m | m1).cumsum().duplicated())

Out[159]:
0      True
1     False
2     False
3      True
4      True
5      True
6      True
7      True
8      True
9      True
10     True
11     True
12     True
13     True
14    False
15    False
16    False
dtype: bool

In [168]: s[m2]
Out[168]:
0    -1
3     0
4    -1
5    -1
6     0
7     0
8    -5
9    -5
10    0
11    0
12    0
13   -1
dtype: int64

Pas à pas :
Je modifie votre échantillon pour inclure le cas -1 ayant 2 lignes consécutives que nous devrions conserver.

m = s.diff().ne(0)
m1 = s.groupby(m.cumsum()).transform(lambda x: x.eq(-1).sum() < 3)
m2 = ~((m | m1).cumsum().duplicated())
s[m2]


0 commentaires