web-dev-qa-db-fra.com

Filtrer les lignes de la base de données si la valeur de la colonne se trouve dans une liste de valeurs définie

J'ai un Python pandas _ DataFrame rpt:

rpt
<class 'pandas.core.frame.DataFrame'>
MultiIndex: 47518 entries, ('000002', '20120331') to ('603366', '20091231')
Data columns:
STK_ID                    47518  non-null values
STK_Name                  47518  non-null values
RPT_Date                  47518  non-null values
sales                     47518  non-null values

Je peux filtrer les lignes dont l'ID de stock est '600809' comme ceci: rpt[rpt['STK_ID'] == '600809']

<class 'pandas.core.frame.DataFrame'>
MultiIndex: 25 entries, ('600809', '20120331') to ('600809', '20060331')
Data columns:
STK_ID                    25  non-null values
STK_Name                  25  non-null values
RPT_Date                  25  non-null values
sales                     25  non-null values

et je veux rassembler toutes les lignes de certaines actions, telles que ['600809','600141','600329']. Cela signifie que je veux une syntaxe comme celle-ci:

stk_list = ['600809','600141','600329']

rst = rpt[rpt['STK_ID'] in stk_list] # this does not works in pandas 

Puisque pandas n'accepte pas la commande ci-dessus, comment atteindre la cible?

365
bigbug

Utilisez la méthode isin. rpt[rpt['STK_ID'].isin(stk_list)].

536
BrenBarn

isin() est idéal si vous avez une liste de correspondances exactes, mais si vous avez une liste de correspondances partielles ou de sous-chaînes à rechercher, vous pouvez filtrer à l'aide de la méthode str.contains et expressions régulières.

Par exemple, si nous souhaitons renvoyer un DataFrame contenant tous les ID de stock commençant par _'600'_ et suivis de trois chiffres:

_>>> rpt[rpt['STK_ID'].str.contains(r'^600[0-9]{3}$')] # ^ means start of string
...   STK_ID   ...                                    # [0-9]{3} means any three digits
...  '600809'  ...                                    # $ means end of string
...  '600141'  ...
...  '600329'  ...
...      ...   ...
_

Supposons maintenant que nous ayons une liste de chaînes avec lesquelles nous voulons que les valeurs dans _'STK_ID'_ se terminent, par ex.

_endstrings = ['01$', '02$', '05$']
_

Nous pouvons joindre ces chaînes avec le caractère regex 'ou' _|_ et passer la chaîne à _str.contains_ pour filtrer le DataFrame:

_>>> rpt[rpt['STK_ID'].str.contains('|'.join(endstrings)]
...   STK_ID   ...
...  '155905'  ...
...  '633101'  ...
...  '210302'  ...
...      ...   ...
_

Enfin, contains peut ignorer la casse (en définissant _case=False_), ce qui vous permet d’être plus général lorsque vous spécifiez les chaînes que vous souhaitez faire correspondre.

Par exemple,

_str.contains('pandas', case=False)
_

correspondrait à PANDAS, PanDAs, _paNdAs123_, etc.

104
Alex Riley

vous pouvez également utiliser des plages en utilisant:

b = df[(df['a'] > 1) & (df['a'] < 5)]
42
yemu

Vous pouvez également directement requête votre DataFrame pour cette information.

rpt.query('STK_ID in (600809,600141,600329)')

Ou de même rechercher des gammes:

rpt.query('60000 < STK_ID < 70000')
37
bscan

Trancher des données avec des pandas

Étant donné un dataframe comme ceci:

    RPT_Date  STK_ID STK_Name  sales
0 1980-01-01       0   Arthur      0
1 1980-01-02       1    Beate      4
2 1980-01-03       2    Cecil      2
3 1980-01-04       3     Dana      8
4 1980-01-05       4     Eric      4
5 1980-01-06       5    Fidel      5
6 1980-01-07       6   George      4
7 1980-01-08       7     Hans      7
8 1980-01-09       8   Ingrid      7
9 1980-01-10       9    Jones      4

Il existe plusieurs façons de sélectionner ou de découper les données.

Utiliser .isin

La plus évidente est la fonction .isin. Vous pouvez créer un masque qui vous donne une série d'instructions True/False, qui peuvent être appliquées à un cadre de données comme ceci:

mask = df['STK_ID'].isin([4, 2, 6])

mask
0    False
1    False
2     True
3    False
4     True
5    False
6     True
7    False
8    False
9    False
Name: STK_ID, dtype: bool

df[mask]
    RPT_Date  STK_ID STK_Name  sales
2 1980-01-03       2    Cecil      2
4 1980-01-05       4     Eric      4
6 1980-01-07       6   George      4

Le masquage est la solution ad-hoc au problème, mais ne fonctionne pas toujours bien en termes de vitesse et de mémoire.

Avec indexation

En définissant l'index sur la colonne STK_ID, nous pouvons utiliser l'objet de découpage pandas intégré .loc

df.set_index('STK_ID', inplace=True)
         RPT_Date STK_Name  sales
STK_ID                           
0      1980-01-01   Arthur      0
1      1980-01-02    Beate      4
2      1980-01-03    Cecil      2
3      1980-01-04     Dana      8
4      1980-01-05     Eric      4
5      1980-01-06    Fidel      5
6      1980-01-07   George      4
7      1980-01-08     Hans      7
8      1980-01-09   Ingrid      7
9      1980-01-10    Jones      4

df.loc[[4, 2, 6]]
         RPT_Date STK_Name  sales
STK_ID                           
4      1980-01-05     Eric      4
2      1980-01-03    Cecil      2
6      1980-01-07   George      4

C'est le moyen rapide de le faire, même si l'indexation peut prendre un peu de temps, cela vous fait gagner du temps si vous souhaitez effectuer plusieurs requêtes de ce type.

Fusion de cadres de données

Cela peut également être fait en fusionnant des images. Cela conviendrait mieux pour un scénario dans lequel vous avez beaucoup plus de données que dans ces exemples.

stkid_df = pd.DataFrame({"STK_ID": [4,2,6]})
df.merge(stkid_df, on='STK_ID')
   STK_ID   RPT_Date STK_Name  sales
0       2 1980-01-03    Cecil      2
1       4 1980-01-05     Eric      4
2       6 1980-01-07   George      4

Remarque

Toutes les méthodes ci-dessus fonctionnent même s'il y a plusieurs lignes avec le même 'STK_ID'

22
firelynx

Vous pouvez également obtenir des résultats similaires en utilisant 'query' et @:

par exemple:

df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})
df = pd.DataFrame({'A' : [5,6,3,4], 'B' : [1,2,3, 5]})
list_of_values = [3,6]
result= df.query("A in @list_of_values")
result
   A  B
1  6  2
2  3  3
6
akuriako

Vous pouvez utiliser query, à savoir:

b = df.query('a > 1 & a < 5')
5
Pedro Lobito