2
votes

Comment prendre la moyenne courante ou mobile de plusieurs fichiers quotidiens

J'ai 11 ans (2007 à 2017) des fichiers quotidiens de température. Il existe un total de 11 * 365 = 4015 fichiers NetCDF. Chaque fichier contient des dimensions de latitude (100,) , de longitude (360,) et une variable de température de celles-ci de taille (360, 100) . Je veux trouver la moyenne (mobile) sur 15 jours à chaque point de la grille en ignorant les valeurs NaN si présentes. Cela signifie que 15 fichiers doivent être utilisés pour trouver la moyenne. J'ai la fonction suivante pour lire tous les fichiers quotidiens à partir d'un dossier. par exemple. moyenne de files_list [0:15] , files_list [1:16] , files_list [2:17] .... , files_list [4000:] doivent être trouvés. Et chaque fichier doit être enregistré en tant que nouveau fichier NetCDF. J'ai une idée de créer un fichier NetCDF. Mais impossible de trouver la moyenne courante ou mobile.

Voici mon code:

def files_list (working_dir, extension):
    '''
    input = working directory and extension of file(eg. *.nc)
    outout = returns the list of files in the folder
    '''
    file_full_path = os.path.join(working_dir)
    os.chdir(working_dir)
    files = glob.glob(os.path.join(file_full_path,extension)) 
    files = natsort.natsorted(files)
    files_list= []       #Empty lsit of files
    j = 0 
    for j in range(0,len(files)):
        files_list.append(os.path.basename(files[j])) #appending each files in a directory to file list 
    return files_list


2 commentaires

Combien d'éléments avez-vous dans chaque fichier? Veuillez partager un extrait d'un tel fichier. Si chaque fichier contient des milliers de points de grille, je commencerais par trier les différents points de grille pour séparer les fichiers. Chaque fichier contiendra le même point de grille pour toutes les dates, triées par date. De cette façon, il serait simple de charger un fichier entier d'un seul point de grille et de calculer une moyenne mobile dessus.


Copie possible de Moyenne mobile ou moyenne courante


3 Réponses :


1
votes

Quant à mon commentaire ci-dessus:

"Combien d'éléments avez-vous dans chaque fichier? ... Si chaque fichier contient des milliers de points de grille, je voudrais Commencez par trier les différents points de la grille pour séparer les fichiers. Chaque Le fichier contiendra le même point de grille pour toutes les dates, triées par date. Ce comment il serait simple de charger un fichier entier d'un seul point de grille et calculez une moyenne mobile dessus. "

Maintenant que vous avez un fichier pour un seul point de grille, je chargerais les données dans une liste et exécuterais ce simple calcul de moyenne courante. (Étant donné que vous avez accès à l'ensemble de données, vous pouvez utiliser ce code. Pour les cas où la moyenne est calculée à l'exécution et où il n'y a pas d'historique des résultats, vous pouvez utiliser les algorithmes spécifiés ici: Wikipedia - Moyenne mobile )

[1, 2, 3, 4, 5, 6, 7, 8, 9]
2.0
3.0
4.0
5.0
6.0
7.0
8.0

Le résultat est: p >

#Generate a list of 10 items
my_gridpoints_data=[x for x in range(1, 11)]
print(my_gridpoints_data)

#The average calculation window is set to 3, so the average is for 3 items at a time
avg_window_width: int = 3
avg: float = 0.0
sum: float = 0.0

# Calculate the average of the first 3 items (avg_window_width is 3)
for pos in range(0, avg_window_width):
    sum = sum + my_gridpoints_data[pos]
avg = sum / avg_window_width
print(avg)

# Then move the window of the average by subtracting the leftmost item 
# and adding a new item from the right
# Do this until the calculation window reaches the list's last item

for pos in range(avg_window_width, my_gridpoints_data.__len__()):
    sum = sum + my_gridpoints_data[pos] - my_gridpoints_data[pos - avg_window_width]
    avg = sum/avg_window_width
    print(avg)


2 commentaires

pourquoi se séparer en points de grille? ce serait une approche extrêmement lente. Si vous effectuez la même opération partout, il n'y a aucune raison pour que vous puissiez opérer sur l'ensemble du domaine.


@AdrianTompkins, j'ai suggéré de séparer les points de la grille avant d'effectuer le calcul, car je n'ai aucune idée de la taille de l'ensemble de données. Nous savons qu'il se compose d'environ 4000 fichiers, mais peut-être que chaque fichier contient des données pour un million de points. L'organisation des données avant le calcul permet un algorithme plus simple pour le calcul de la moyenne.



2
votes

Ce n'est pas une solution en python, mais si vos fichiers sont appelés file_20061105.nc etc etc, vous pouvez les fusionner avec cdo (opérateurs de données climatiques) à partir de la ligne de commande puis utiliser la fonction runmean

for year in {2007..2017} ; do 
  cdo mergetime file_${year}????.nc merged_${year}.nc
done
cdo mergetime merged_????.nc merged_file.nc
cdo runmean,15 merged_file.nc runmean.nc


0 commentaires

0
votes

Un peu tard pour répondre mais pour quelqu'un qui lira à l'avenir, xarray fournit également une solution Pythonic simple très similaire à la réponse @Adrian Tomkins, où l'on peut d'abord fusionner les fichiers de chaque année, puis fusionner les ensemble dans un fichier en raison de la limite du nombre de fichiers qui peuvent être ouverts dans un système.

for yr in range(2011,2018):
    file_name = str(yr) + 'merge.nc'
    xr.open_mfdataset(str(yr)*, combine='nested', concat_dim='time').to_netcdf(file_name)

xr.open_mfdataset(*merge.nc, combine='nested', concat_dim='time').to_netcdf(merge_all.nc)
ds = xr.open_dataset(merge_all.nc, chunks={'lat'=10, 'lon'=10}) # option to chunk if file size is too large, can also be used earlier with open_mfdataset
ds_rolling_mean = ds.rolling(time=15, center=True).mean()

Edit: Un gros avantage de xarray par rapport aux autres classiques C'est que l'on peut facilement faire des calculs en dehors de la mémoire et mettre à l'échelle vos calculs sur plusieurs cœurs grâce à dask . Par exemple, si vous devez effectuer un prétraitement de vos fichiers avant la fusion, alors xr.open_mfdataset prend une fonction de prétraitement définie par l'utilisateur comme argument preprocess et définissant 'parallel = True 'pré-traitera vos fichiers d'entrée en parallèle avant la fusion.


0 commentaires