J'ai ce dataframe:

In[1]df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
In[2]df
Out[2]: 
    0   1   2   3   4
0   1   2   3   4   5
1   6   7   8   9  10
2  11  12  13  14  15
3  16  17  18  19  20
4  21  22  23  24  25

Je dois y parvenir:

  1. pour chaque ligne de ma trame de données,
  2. si 2 ou plusieurs valeurs dans 3 cellules consécutives sont supérieures à 10,
  3. alors la dernière de ces 3 cellules doit être marquée comme True.

La trame de données résultante df1 doit être de la même taille avec Vrai ou Faux en fonction des critères énoncés ci-dessus:

In[3]df1
Out[3]: 
    0   1      2      3      4
0 NaN NaN  False  False  False
1 NaN NaN  False  False  False
2 NaN NaN   True   True   True
3 NaN NaN   True   True   True
4 NaN NaN   True   True   True
  • df1.iloc [0,1] est une bacause NaN dans cette cellule, seulement deux nombres ont été donnés mais il fallait au moins 3 nombres pour faire le test.
  • df1.iloc [1,3] est Faux car aucun dans [7,8,9] n'est supérieur à 10
  • df1.iloc [3,4] est vrai car 2 ou plus dans [18,19,20] est supérieur à 10

J'ai pensé que dataframe.rolling.apply () avec une fonction pourrait être la solution, mais comment exactement?

2
Yi Fang 15 avril 2018 à 06:52

3 réponses

Meilleure réponse

Vous avez raison: utiliser rolling() est la solution. Cependant, vous devez garder à l'esprit puisque rolling() remplace la valeur à la fin de la fenêtre par la nouvelle valeur, vous ne pouvez donc pas simplement marquer la fenêtre avec True, vous obtiendrez également False chaque fois la condition n'est pas applicable

Voici le code qui utilise votre exemple de trame de données et effectue la transformation souhaitée:

df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])

Maintenant, définir une fonction qui prend une fenêtre en argument et retourne si la condition est remplie

def fun(x):
    num = 0
    for i in x:
        num += 1 if i > 10 else 0
    return 1 if num >= 2 else -1

J'ai codé en dur le seuil à 10. Donc, si dans une fenêtre le nombre de valeurs supérieures à 10 est supérieur ou égal à 2, la dernière valeur est remplacée par 1 (dénotant Vrai), sinon elle est remplacée par -1 (dénotant Faux ).

Si vous souhaitez conserver les paramètres de seuil en tant que variables, consultez la cette réponse pour les passer en arguments.

Maintenant, en appliquant la fonction sur la fenêtre déroulante, en utilisant la taille de la fenêtre comme 3, l'axe 1 et en plus si vous ne voulez pas NaN, vous pouvez également définir min_periods à 1 dans les arguments.

df.rolling(3, axis=1).apply(fun)

Produit la sortie comme

  0   1    2    3    4
0 NaN NaN -1.0 -1.0 -1.0
1 NaN NaN -1.0 -1.0 -1.0
2 NaN NaN  1.0  1.0  1.0
3 NaN NaN  1.0  1.0  1.0
4 NaN NaN  1.0  1.0  1.0
2
penguin2048 15 avril 2018 à 12:05

Utilisez sum sur une trame de données booléenne.

df.gt(10).rolling(3, axis=1).sum().ge(2)

       0      1      2      3      4
0  False  False  False  False  False
1  False  False  False  False  False
2  False  False   True   True   True
3  False  False   True   True   True
4  False  False   True   True   True

Vous pouvez définir la sortie exacte demandée en masquant où na.

df.gt(10).rolling(3, axis=1).sum().pipe(lambda d: d.ge(2).mask(d.isna()))

    0   1      2      3      4
0 NaN NaN  False  False  False
1 NaN NaN  False  False  False
2 NaN NaN   True   True   True
3 NaN NaN   True   True   True
4 NaN NaN   True   True   True
2
piRSquared 15 avril 2018 à 08:19

Vous avez besoin -

import pandas as pd
import numpy as np
df = pd.DataFrame([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20],[21,22,23,24,25]])
df1 = df.apply(lambda x: pd.Series([np.nan, np.nan]+[all(j>10 for j in i) for i in zip(x[0::1], x[1::1], x[2::1])]), axis=1)

print(df1)

Sortie

0   1      2      3      4
0 NaN NaN  False  False  False
1 NaN NaN  False  False  False
2 NaN NaN   True   True   True
3 NaN NaN   True   True   True
4 NaN NaN   True   True   True

Explication

list(zip(x[0::1], x[1::1], x[2::1])

Le décompose en prenant 3 colonnes à la fois pour chaque ligne -

0             [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
1            [(6, 7, 8), (7, 8, 9), (8, 9, 10)]
2    [(11, 12, 13), (12, 13, 14), (13, 14, 15)]
3    [(16, 17, 18), (17, 18, 19), (18, 19, 20)]
4    [(21, 22, 23), (22, 23, 24), (23, 24, 25)]

all(j>10 for j in i)

Vérifie chaque élément de la liste des tuples puis affiche True si tous les éléments du tuple sont supérieurs à 10

Concaténer [np.nan, np.nan] pour correspondre à votre sortie. J'espère que cela pourra aider.

0
Vivek Kalyanarangan 15 avril 2018 à 07:09