3 votes

Comparaison numérique entre les éléments d'une colonne d'un cadre de données Pandas et une liste.

J'ai 3 dataframes pandas à colonnes multiindex.

cadre de données 1 (valeur minimale) :

  |  A    |   B   |  C   |
  |  Min  |  Min  |  Min |
  |-------|-------|------|
0 | 26.47 | 17.31 | 1.26 |
1 | 27.23 | 14.38 | 1.36 |
2 | 27.23 | 18.88 | 1.28 |

dataframe 2 (valeur utilisée pour la comparaison)

La ligne 0, la ligne 1 et la ligne 2 sont les mêmes, j'étend le cadre de données à trois lignes pour la comparaison avec les cadres de données min et max. La valeur dans chaque cellule du dataframe est un tableau de données.

  |          A          |           B           |          C         |
  |         Val         |          Val          |         Val        |
  |---------------------|-----------------------|--------------------|
0 | [27.58,28.37,28.73] | [17.31, 18.42, 18.72] | [1.36, 1.28, 1.27] |
1 | [27.58,28.37,28.73] | [17.31, 18.42, 18.72] | [1.36, 1.28, 1.27] |
2 | [27.58,28.37,28.73] | [17.31, 18.42, 18.72] | [1.36, 1.28, 1.27] |

cadre de données 3 (valeur maximale) :

  |  A    |   B   |  C   |
  |  Max  |  Max  |  Max |
  |-------|-------|------|
0 | 28.68 | 18.42 | 1.37 |
1 | 29.50 | 17.31 | 1.47 |
2 | 29.87 | 20.45 | 1.39 |

Résultat escompté :

  |          A          |           B           |          C           |
  |        Result       |          Result       |         Result       |
  |---------------------|-----------------------|----------------------|
0 | [True, True, False] |  [True, True, False]  | [True, True, True]   |
1 | [True, True, True]  | [True, False, False]  | [True, False, False] |
2 | [True, True, True]  | [False, False, False] | [True, True, False]  |

J'aimerais effectuer une comparaison par éléments de cette manière :

min <= each element in ndarray <= max

i.e

for row 0:

26.47 <= [27.58,28.37,28.73] <= 28.68

17.31 <= [17.31, 18.42, 18.72] <= 18.42

1.26 <= [1.36, 1.28, 1.27] <= 1.37

et ainsi de suite

J'ai essayé ( datafram2 >= dataframe3 ) & ( datafram2 <= datafram3 ) mais pas le travail.

Quel est le moyen le plus simple et le plus rapide de calculer le résultat ?

Exemple de code de dataframe :

min_columns = pd.MultiIndex.from_product( [ [ 'A', 'B', 'C' ], [ 'Min' ] ] )
val_columns = pd.MultiIndex.from_product( [ [ 'A', 'B', 'C' ], [ 'Val' ] ] )
max_columns = pd.MultiIndex.from_product( [ [ 'A', 'B', 'C' ], [ 'Max' ] ] )

min_df = pd.DataFrame( [ [ 26.47, 17.31, 1.26 ], [ 27.23, 14.38, 1.36 ], [ 27.23, 18.88, 1.28 ] ], columns=min_columns )
val_df = pd.DataFrame( [ [ [ 27.58, 28.37, 28.73 ], [ 17.31, 18.42, 18.72], [1.36, 1.28, 1.27 ] ] ] , columns=val_columns )
max_df = pd.DataFrame( [ [ 28.68, 18.42, 1.37 ], [ 29.50, 17.31, 1.47 ], [ 29.87, 20.45, 1.39 ] ] , columns=max_columns )

3voto

Nk03 Points 12534

Si vous avez des cadres de données comme ceux-ci :

df1 = pd.DataFrame({'AMin': {0: 26.47, 1: 27.23, 2: 27.23},
 'BMin': {0: 17.31, 1: 14.38, 2: 18.88},
 'CMin': {0: 1.26, 1: 1.36, 2: 1.28}})

df2 = pd.DataFrame({'AVal': {0: [27.58, 28.37, 28.73],
  1: [27.58, 28.37, 28.73],
  2: [27.58, 28.37, 28.73]},
 'BVal': {0: [17.31, 18.42, 18.72],
  1: [17.31, 18.42, 18.72],
  2: [17.31, 18.42, 18.72]},
 'CVal': {0: [1.36, 1.28, 1.27], 1: [1.36, 1.28, 1.27], 2: [1.36, 1.28, 1.27]}})

df3 = pd.DataFrame({'AMax': {0: 28.68, 1: 29.5, 2: 29.87},
 'BMax': {0: 18.42, 1: 17.31, 2: 20.45},
 'CMax': {0: 1.37, 1: 1.47, 2: 1.39}})

Alors vous pouvez explode le 2ème cadre de données et comparez les valeurs.

m = df2.apply(pd.Series.explode).values
df = pd.DataFrame(
    (df1.iloc[np.arange(len(df1)).repeat(3)].values <= m) &
    (m <= df3.iloc[np.arange(len(df3)).repeat(3)].values),
    columns=df2.columns
)

df = df.groupby(df.index // 3).agg(list)

SORTIE :

                     A                      B                     C
0  [True, True, False]    [True, True, False]    [True, True, True]
1   [True, True, True]   [True, False, False]  [True, False, False]
2   [True, True, True]  [False, False, False]   [True, True, False]

3voto

Pygirl Points 358

Il suffit de transformer les valeurs des colonnes en tableaux NumPy et de les traiter comme un problème de comparaison de tableaux (par ligne).

Vous pouvez utiliser apply :

def bool_check(row):
    col = row.name[0]
    min_val = df1[pd.IndexSlice[col]].to_numpy()
    max_val = df3[pd.IndexSlice[col]].to_numpy()
    x = np.array(row.tolist())
    return list((x >= min_val) & (x <= max_val))

res = df2.apply(bool_check,axis=0).rename(columns={'Val':'Result'})

res :

A

B

C

Résultat

Résultat

Résultat

0

[Vrai, Vrai, Faux]

[Vrai, Vrai, Faux]

[Vrai, Vrai, Vrai]

1

[Vrai, Vrai, Vrai]

[Vrai, Faux, Faux]

[Vrai, Faux, Faux]

2

[Vrai, Vrai, Vrai]

[Faux, Faux, Faux]

[Vrai, Vrai, Faux]

Mise à jour

(Solution complète basée sur les données que vous avez fournies) :

def bool_check(row):
    col = row.name[0]
    min_val = min_df[pd.IndexSlice[col]].to_numpy()
    max_val = max_df[pd.IndexSlice[col]].to_numpy()
    x = np.array(row.tolist())
    return list((x >= min_val) & (x <= max_val))

res = val_df.apply(bool_check,axis=0).rename(columns={'Val':'Result'})

Comparaison des temps :

Méthode 1 (méthode de Nk031) :

Temps CPU : utilisateur 19.5 ms, sys : 0 ns, total : 19,5 ms Temps du mur : 18,9 ms

Méthode 2 (méthode de Nk032) :

Temps CPU : utilisateur 23 ms, sys : 102 µs, total : 23,1 ms Temps de paroi : 21,9 ms

Méthode 3 (Utilisation de la comparaison basée sur numpy) :

Temps CPU : utilisateur 8,76 ms, sys : 26 µs, total : 8,79 ms Temps de paroi : 8,91 ms

La solution mise à jour et optimisée de Nk03 :

Temps CPU : utilisateur 16 ms, sys : 0 ns, total : 16 ms Temps de paroi : 15.5 ms

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X