Как рассчитать среднемесячные температуры за каждый год отдельно, используя NumPy? - PullRequest
2 голосов
/ 04 июля 2019

Итак, у меня есть набор данных с температурами с 1952 по 2017 год. Мне нужно рассчитывать среднемесячные температуры для каждого года отдельно.

Dataset: https://drive.google.com/file/d/1_RZPLaXoKydjjgm4ghkwtbOGWKC4-Ssc/view?usp=sharing

import numpy as np
fp = 'data/1091402.txt'
data = np.genfromtxt(fp, skip_header=2, usecols=(4, 5, 6, 7, 8))
data_mask = (data<-9998)
data[data_mask] = np.nan
date = data[:, 0]
precip = data[:, 1]
tavg = data[:, 2]
tmax = data[:, 3]
tmin = data[:, 4]

Печать первых пяти строк данных дает следующее: (первая - дата, затем количество осадков, tavg (средняя температура), tmax и tmin)

[[1.9520101e+07 3.1000000e-01 3.7000000e+01 3.9000000e+01 3.4000000e+01]
 [1.9520102e+07           nan 3.5000000e+01 3.7000000e+01 3.4000000e+01]
 [1.9520103e+07 1.4000000e-01 3.3000000e+01 3.6000000e+01           nan]
 [1.9520104e+07 5.0000000e-02 2.9000000e+01 3.0000000e+01 2.5000000e+01]
 [1.9520105e+07 6.0000000e-02 2.7000000e+01 3.0000000e+01 2.5000000e+01]]

Здесь я удаляю значения nan и отсутствующие данные из tavg:

missing_tmax_mask =  ~np.isfinite(tmax)
np.count_nonzero(missing_tmax_mask)
tmax_mask = np.isfinite(tmax)
tmax_clean = tmax[tmax_mask]
date_clean = date[tmax_mask]
print (tmax_clean)
[39. 37. 36. ... 48. 49. 56.]

Преобразование их в int и строку снова, чтобы удалить 'YYYYMMDD.0' и получить 'YYYYMMDD'

date_clean_int = date_clean.astype(int)
date_clean_str = date_clean_int.astype(str)

Печать date_clean_str дает следующее:

['19520101' '19520102' '19520103' ... '20171001' '20171002' '20171004']

Создание массива год, месяц и день в формате «ГГГГ», «ММ» и «ДД»:

year = [datenow[0:4] for datenow in date_clean_str]
year = np.array(year)
month = [d[4:6] for d in date_clean_str]
month = np.array(month)
day = [datenow[6:8] for datenow in date_clean_str]
day = np.array(day)

Печать года, месяца и дня дает следующее:

['1952' '1952' '1952' ... '2017' '2017' '2017']
['01' '01' '01' ... '10' '10' '10']
['01' '02' '03' ... '01' '02' '04']

Здесь вычисляются средние значения за месяц, включая все годы:

means_months = np.zeros(12)
index = 0
for month_now in np.unique(month):
    means_months[index] = tmax_clean[(month == month_now) & (year < '2017')].mean()
    index = index + 1

Вот расчёт за каждый год:

means_years = np.zeros(65)
index = 0
for year_now in np.unique(year):
    means_years[index] = tmax_clean[(year == year_now) & (year < '2017')].mean()
    index = index+1

Но я хочу знать, как рассчитывать каждый месяц и разделять по месяцам и годам, используя numpy и приведенный выше код. Общее количество значений будет 780 = 65 лет х 12 месяцев. Я предпочел бы иметь ответ в форме, как указано выше, если это возможно. Что-то вроде:

means_year_month = np.zeros(780)
index = 0
for ….

Здесь я заблудился. Может быть, использовать словарь с {YYYY: MM ...} ???

Ответы [ 3 ]

2 голосов
/ 04 июля 2019
b=pd.read_csv('b.dat')

b['date']=pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')

b.index=b['date']

b.index.month # will give you indexes of months (can access the month like this)

df.groupby(by=[b.index.month])

или год или день, а затем вычислите, опаздывая среднее простое.

Вы пробовали это? это быстрый и эффективный способ.

0 голосов
/ 04 июля 2019

Я не уверен, что использовал бы NumPy для группировки, но похоже, что вы в порядке с пандами. Вот как это можно сделать:

import pandas as pd
import datetime as dt

# This command is executed in shell due to '!' sign. 
# It replaces all extra whitespaces with single one.
!cat 1091402.txt | sed 's/ \{1,\}/ /g' > 1091402_trimmed.txt
df = pd.read_csv('1091402_trimmed.txt', sep=' ')

# Omit line with hyphens
df = df[1:]
# Parse datetime
df['date'] = pd.to_datetime(df['DATE'])
# Extract year and month
df['year'] = df['date'].apply(lambda x: x.year)
df['month'] = df['date'].apply(lambda x: x.month)
for column in ('TMAX', 'TMIN', 'TAVG'):
    # Set N/A for -9999 values
    df[column].replace('-9999', None, inplace=True) 
    # Cast all columns to int
    df[column] = df[column].astype('int64')
# Grouping
df.groupby(['year', 'month']).agg({
    'TAVG': ['mean', 'median'],
    'TMAX': ['mean', 'median'],
    'TMIN': ['mean', 'median'],
}).head()

Выходы:

Out[1]:
                 TAVG              TMAX              TMIN
                 mean median       mean median       mean median
year month
1952 1      29.478261   29.0  32.608696   30.0  28.434783   28.0
     2      24.800000   26.0  29.000000   28.0  18.400000   19.0
     3      13.807692   10.5  26.423077   25.0   1.230769   -4.0
     4      39.607143   38.0  49.035714   48.0  30.285714   30.0
     5      44.666667   44.0  52.555556   54.0  33.629630   34.0
0 голосов
/ 04 июля 2019

Возможно, использование pandas.read_fwf() работает лучше.

import pandas as pd

df = pd.read_fwf('1091402.txt')
df.index = pd.to_datetime(df['DATE'], format='%Y%m%d')
df = df[['TMIN', 'TMAX']]
df = df[df['TMIN'] != -9999][df['TMAX'] != -9999]
print(df.shape)
# print(df)

print()
print('{:7s} | {:12s} | {:12s} | {:12s}'.format(
    'year', 'num_records', 'avg TMIN', 'avg TMAX'))
for key, sub_df in df.groupby(df.index.year):
    print('{:7d} | {:12d} | {:12.1f} | {:12.1f}'.format(
        key,
        sub_df.shape[0],
        sub_df['TMIN'].mean(),
        sub_df['TMAX'].mean()))

print()
print('{:7s} | {:12s} | {:12s} | {:12s}'.format(
    'period', 'num_records', 'avg TMIN', 'avg TMAX'))
for key, sub_df in df.groupby([df.index.year, df.index.month]):
    print('{:4d}-{:02d} | {:12d} | {:12.1f} | {:12.1f}'.format(
        key[0],
        key[1],
        sub_df.shape[0],
        sub_df['TMIN'].mean(),
        sub_df['TMAX'].mean()))

Вывод:

year    | num_records  | avg TMIN     | avg TMAX    
  1952  |          240 |         32.5 |         48.0
  1953  |          255 |         35.9 |         50.9
  1954  |          246 |         36.4 |         49.7
  1955  |          265 |         31.2 |         46.4
  1956  |          260 |         31.0 |         47.1
...

period  | num_records  | avg TMIN     | avg TMAX    
1952-01 |           10 |         27.5 |         35.1
1952-02 |           18 |         17.2 |         28.8
1952-03 |           20 |         -1.1 |         25.6
1952-04 |           23 |         30.1 |         49.7
1952-05 |           21 |         33.6 |         52.9
...
...