2
votes

Comment remplir des dataframes pandas en boucle?

J'essaie de créer un sous-ensemble de dataframes à partir d'un dataframe plus grand en recherchant une chaîne dans les en-têtes de colonne.

[27884 rows x 10 columns]
       N9_Inj_Casing_Gas_Valve  ...  N9_Inj_Casing_Gas_Pressure
0                    74.375000  ...                 2485.602364
1                    74.520833  ...                 2485.346000
2                    74.437500  ...                 2485.341091

J'essaye de rechercher le nom de puits dans les colonnes de dataframe cdf et placez les colonnes qui contiennent ce nom de puits dans une nouvelle trame de données nommée le nom de puits.

Je suis capable de construire mes nouvelles sous-trames de données mais les trames de données sont vides de taille (0, 0) alors que cdf est (21973 , 91).

well_cols se remplit également correctement sous forme de liste.

Voici quelques-uns des en-têtes de colonne cdf. Chaque colonne contient 20 000 lignes de données.

Index(['N1_Inj_Casing_Gas_Valve', 'N1_LT_Stm_Rate', 'N1_ST_Stm_Rate',
       'N1_Inj_Casing_Gas_Flow_Rate', 'N1_LT_Stm_Valve', 'N1_ST_Stm_Valve',
       'N1_LT_Stm_Pressure', 'N1_ST_Stm_Pressure', 'N1_Bubble_Tube_Pressure',
       'N1_Inj_Casing_Gas_Pressure', 'N2_Inj_Casing_Gas_Valve',
       'N2_LT_Stm_Rate', 'N2_ST_Stm_Rate', 'N2_Inj_Casing_Gas_Flow_Rate',
       'N2_LT_Stm_Valve', 'N2_ST_Stm_Valve', 'N2_LT_Stm_Pressure',
       'N2_ST_Stm_Pressure', 'N2_Bubble_Tube_Pressure',
       'N2_Inj_Casing_Gas_Pressure', 'N3_Inj_Casing_Gas_Valve',
       'N3_LT_Stm_Rate', 'N3_ST_Stm_Rate', 'N3_Inj_Casing_Gas_Flow_Rate',
       'N3_LT_Stm_Valve', 'N3_ST_Stm_Valve', 'N3_LT_Stm_Pressure',

Je veux créer un nouveau dataframe avec chaque en-tête qui contient le "bien" IE un nouveau dataframe pour toutes les colonnes et données avec le nom de colonne contenant N1, un autre pour N2 etc. .

Les New dataframes se remplissent correctement à l'intérieur de la boucle mais disparaissent lorsque la boucle se rompt ... un peu de la sortie de code pour print (well) :

XXX


1 commentaires

Pourriez-vous s'il vous plaît ajouter quelques exemples de données et une sortie souhaitée afin que nous puissions vous aider plus facilement?


4 Réponses :


2
votes

IIUC cela devrait suffire:

df=pd.read_csv('data.csv')
cdf = df.drop(['DateTime'], axis=1)

wells = ['N1','N2','N3','N4','N5','N6','N7','N8','N9']
well_dict={}
for well in wells:

    well_cols = [col for col in cdf.columns if well in col]
    well_dict[well] = cdf[well_cols]

Les dictionnaires sont généralement la voie à suivre si vous voulez renseigner quelque chose. Dans ce cas, si vous entrez well_dict ['N1'] , vous obtiendrez votre premier dataframe, et ainsi de suite.


7 commentaires

mes dataframes sont toujours vides à ce sujet.


Pourriez-vous publier les 10 premiers éléments de cdf.columns ?


Dans le message d'origine.


si vous ajoutez print (cdf.shape) après well = cdf [well_cols] est-ce toujours 0?


Non, il s'agit de la taille de la trame de données d'origine. En fait, mes dataframes se remplissent correctement si j'imprime alors que je suis encore à l'intérieur de la boucle, elles disparaissent juste après la fin de la boucle.


Comme je l'ai mentionné dans ma réponse, les éléments d'une liste ne sont pas modifiables dans une boucle for. Autrement dit, à l'intérieur de votre boucle for, il va affecter l'élément courant à une variable nommée well . Si vous attribuez quelque chose à well dans le bloc de code de la boucle for, cela ne change que pour cette variable (locale), pas pour l'élément de la liste. Cela signifie que dès que vous entrez la prochaine itération, cette valeur est perdue, puisque well contiendra désormais la valeur suivante dans la liste. Voir la deuxième partie de ma réponse pour savoir comment modifier réellement la valeur du tableau.


J'ai modifié ma réponse avec une meilleure compréhension de votre problème. L'enregistrement dans un dictionnaire est généralement préférable à une liste, car ils sont plus flexibles



1
votes

Les éléments d'un tableau ne sont pas modifiables lors de l'itération dessus. Autrement dit, voici ce qu'il fait en fonction de votre exemple:

df=pd.read_csv('data.csv')
cdf = df.drop(['DateTime'], axis=1)

wells = ['N1','N2','N3','N4','N5','N6','N7','N8','N9']
for ix, well in enumerate(wells):
    well_cols = [col for col in cdf.columns if well in col]
    wells[ix] = cdf[well_cols]

Mais à aucun moment vous n'avez changé le tableau, ni stocké les nouvelles dataframes d'ailleurs (même si vous auriez toujours la dernière dataframe stockés dans well à la fin de l'itération).

IMO, il semble que stocker les dataframes dans un dict serait plus facile à utiliser:

df=pd.read_csv('data.csv')
cdf = df.drop(['DateTime'], axis=1)

wells = ['N1','N2','N3','N4','N5','N6','N7','N8','N9']
well_dfs = {}
for well in wells:
    well_cols = [col for col in cdf.columns if well in col]
    well_dfs[well] = cdf[well_cols]

Cependant, si vous le voulez vraiment dans une liste, vous pouvez faire quelque chose comme:

# 1st iteration
well = 'N1' # assigned by the for loop directive
...
well = <empty DataFrame> # assigned by `well = pd.DataFrame()`
...
well = <DataFrame, subset of cdf where col has 'N1' in name> # assigned by `well = cdf[well_cols]`
# 2nd iteration
well = 'N2' # assigned by the for loop directive
...
well = <empty DataFrame> # assigned by `well = pd.DataFrame()`
...
well = <DataFrame, subset of cdf where col has 'N2' in name> # assigned by `well = cdf[well_cols]`
...


6 commentaires

Merci .. Je suis assez nouveau en python et je vois maintenant que j'ai ma nouvelle variable de dictionnaire contenant toutes les données. Je dois ensuite effectuer de nombreuses étapes de nettoyage des données sur les dataframes, ce que j'espérais également faire dans la boucle. J'essaye alors de créer un modèle d'ensemble basé sur les "puits" individuels dans les données. Je devrai peut-être acquérir de nouvelles compétences pour travailler maintenant avec ces sous-cadres de données de dictionnaire que j'avais l'habitude de faire auparavant avec la bibliothèque générale pandas. Il pourrait y avoir un moyen plus simple de créer mes modèles d'ensemble en utilisant simplement le dataframe principal ...


@MA Pas de soucis. Vous pouvez écrire des fonctions qui font ce que vous voulez sur chaque DataFrame, puis parcourir vos valeurs dict et les transmettre à la fonction. Sans en savoir plus sur vos données et ce que vous essayez d'accomplir, je ne peux pas être plus précis. Cependant, si cela a aidé à résoudre votre question actuelle, n'hésitez pas à l'accepter et / ou à la voter :)


Puis-je transformer ces sous-cadres de données du dictionnaire en cadres de données réels en dehors de la boucle? par exemple: N1 = DataFrame.from_dict ou quelque chose (je vais avoir besoin de rechercher la syntaxe)


@MA le dict contiendrait simplement une référence à chacune des dataframes, elles vivent déjà «en dehors de la boucle». Vous pouvez ensuite accéder aux dataframes via le dict. Par exemple, si vous vouliez le dataframe N1, vous feriez simplement well_dfs ['N1'] . Si vous voulez vraiment avoir une variable nommée N1, vous pouvez attribuer les sous-dataframes à: globals () [well] dans la boucle for à la place. Cela créerait une variable nommée w / e est la valeur stockée dans well dans la portée globale. Cependant, c'est assez piraté et n'est pas recommandé pour le code de «production».


Génial merci beaucoup! J'ai un peu hésité à commencer à travailler avec les dictionnaires mais ils semblent faciles. Comme dernière question: comment appeler une colonne particulière à partir de l'une des dataframes du dictionnaire? pour Ex si je voulais ajouter une colonne à une autre .. quelque chose comme well_dfs ['N1': 'LT_Stm_Rate'] ?


@MA vous feriez well_dfs ['N1'] ['LT_Stm_Rate'] . Cependant, d'après votre exemple, vous n'auriez pas de colonne nommée LT_Stm_Rate ; vous auriez plutôt N1_LT_Stm_Rage puisque vous n'avez jamais supprimé le N1_ du nom de la colonne. Il serait peut-être préférable de supprimer cela en utilisant quelque chose comme wells [ix] .rename (lambda x: x.replace (well + '_', ''), axis = 1, inplace = True) dans la boucle for, cela faciliterait l'écriture de fonctions pour agir sur chaque dataframe.



0
votes

Utilisation de contains

df[df.columns.str.contains('|'.join(wells))]


0 commentaires

1
votes

Une manière d'aborder le problème est d'utiliser pd.MultiIndex et Groupby .

Vous pouvez ajouter la construction d'un MultiIndex composé d'un identifiant de puits et d'un nom de variable. Si vous avez df:

import pandas as pd
from io import StringIO

data = """
N1_a,N1_b,N2_a,N2_b
1,2,2,3,4
2,7,8,9,10
"""

df = pd.read_csv(StringIO(data)) 

# Parse Column names to add well name to multiindex level
df = pd.DataFrame(df.values, columns=df.columns.str.split('_', expand=True)).sort_index(1)

# Group by well name
grouped = df.T.groupby(level=0)

#bulist list of sub dataframes
wells = [group.T for _, group in grouped]

Vous pouvez utiliser df.columns.str.split ('_', expand = True) pour analyser le nom de la variable correspondant à l'identifiant du puits (c'est-à-dire a ou b).

  N2    
   a   b
0  3   4
1  9  10

Ce qui renvoie:

  N1   
   a  b
0  2  2
1  7  8

Ensuite, vous pouvez transposer le bloc de données et groupby le niveau MultiIndex 0.

wells = [group.T for _, group in grouped]

Pour renvoyer une liste de trames de sous-données non transposées, vous pouvez utiliser:

grouped = df.T.groupby(level=0)

puits [0] est:

  N1    N2    
   a  b  a   b
0  2  2  3   4
1  7  8  9  10

et puits [1] est:

df = pd.DataFrame(df.values, columns=df.columns.str.split('_', expand=True)).sort_index(1)

La dernière étape est plutôt inutile car les données sont accessibles à partir de l'objet groupé grouped .

Tous ensemble:

   N1_a  N1_b  N2_a  N2_b
1     2     2     3     4
2     7     8     9    10


0 commentaires