Генерация ежемесячных средств для всех столбцов без инициализации списка для каждого столбца?

#python #loops #apply #transformation

#python #циклы #применить #преобразование

Вопрос:

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

Как я могу адаптировать свой код для автоматического заполнения имен и значений столбцов в фрейм данных с тысячами столбцов?

Для контекста эти данные содержат 20 наблюдений в час в течение 12 месяцев.

Исходные данные:

 timestamp    56TI1164   56FI1281    56TI1281    52FC1043    57TI1501

2016-12-31 23:55:00 117.9673    17876.27    39.10074    9302.815    49.23963
2017-01-01 00:00:00 118.1080    17497.48    39.10759    9322.773    48.97919
2017-01-01 00:05:00 117.7809    17967.33    39.11348    9348.223    48.94284
 

Вывод:

     56TI1164    56FI1281    56TI1281    52FC1043    57TI1501
0   106.734147  16518.428734    16518.428734    7630.187992 45.992215
1   115.099825  18222.911023    18222.911023    9954.252911 47.334477
2   111.555504  19090.607211    19090.607211    9283.845649 48.939581
3   102.408996  18399.719852    18399.719852    7778.897037 48.130057
4   118.371951  20245.378742    20245.378742    9024.424210 64.796939
5   127.580516  21859.212675    21859.212675    9595.477455 70.952311
6   134.159082  22349.853561    22349.853561    10305.252112    75.195480
7   137.990638  21122.233427    21122.233427    10024.709142    74.755469
8   144.958318  18633.290818    18633.290818    11193.381098    66.776627
9   122.406489  20258.135923    20258.135923    10504.604420    61.793355
10  104.817850  18762.070668    18762.070668    9361.052983 51.802615
11  106.589672  20049.809554    20049.809554    9158.685383 51.611633
 

Успешный код:

 #separate data into months
v = list(range(1,13))
data_month = []

for i in v:
    data_month.append(data[(data.index.month==i)])


# average per month for each sensor

mean_56TI1164 = []
mean_56FI1281 = []
mean_56TI1281 = []
mean_52FC1043 = []
mean_57TI1501 = []

for i in range(0,12):


    mean_56TI1164.append(data_month[i]['56TI1164'].mean())
    mean_56FI1281.append(data_month[i]['56FI1281'].mean())
    mean_56TI1281.append(data_month[i]['56FI1281'].mean())
    mean_52FC1043.append(data_month[i]['52FC1043'].mean())
    mean_57TI1501.append(data_month[i]['57TI1501'].mean())


   mean_df = {'56TI1164': mean_56TI1164, '56FI1281': mean_56FI1281, '56TI1281': mean_56TI1281, '52FC1043': mean_52FC1043, '57TI1501': mean_57TI1501}

mean_df = pd.DataFrame(mean_df, columns= ['56TI1164', '56FI1281', '56TI1281', '52FC1043', '57TI1501']) 

mean_df

 

Неудачная попытка сконденсировать:

 col = list(data.columns)
mean_df = pd.DataFrame()

for i in range(0,12):

    for j in col:

        mean_df[j].append(data_month[i][j].mean())

mean_df
 

Комментарии:

1. Это выглядит как отличный вариант использования для извлечения месяца из метки времени, а затем использования df.groupby(month).mean()

Ответ №1:

Как было предложено Г. Андерсоном, вы можете использовать groupby, как в этом примере:

 import pandas as pd
import io

csv="""timestamp    56TI1164   56FI1281    56TI1281    52FC1043    57TI1501
2016-12-31 23:55:00 117.9673    17876.27    39.10074    9302.815    49.23963
2017-01-01 00:00:00 118.1080    17497.48    39.10759    9322.773    48.97919
2017-01-01 00:05:00 117.7809    17967.33    39.11348    9348.223    48.94284
2018-01-01 00:05:00 120.0000    17967.33    39.11348    9348.223    48.94284
2018-01-01 00:05:00 124.0000    17967.33    39.11348    9348.223    48.94284"""

# The following lines read your data into a pandas dataframe;
# it may help if your data comes in the form you wrote in the question

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
data = pd.read_csv(io.StringIO(csv), sep='s (?!dd:dd:dd)', 
                   date_parser=dateparse, index_col=0, engine='python')


# Here is where your data is resampled by month and mean is calculated

data.groupby(pd.Grouper(freq='M')).mean()

# If you have missing months, use this instead:
#data.groupby(pd.Grouper(freq='M')).mean().dropna()
 

Результатом data.groupby(pd.Grouper(freq='M')).mean().dropna() будет:

             56TI1164    56FI1281    56TI1281    52FC1043    57TI1501
timestamp                   
2016-12-31  117.96730   17876.270   39.100740   9302.815    49.239630
2017-01-31  117.94445   17732.405   39.110535   9335.498    48.961015
2018-01-31  122.00000   17967.330   39.113480   9348.223    48.942840
 

Пожалуйста, обратите внимание, что раньше я data.groupby(pd.Grouper(freq='M')).mean().dropna() избавлялся от NaN недостающих месяцев (я добавил некоторые данные за январь 2018 года, пропустив то, что находится между ними).

Также обратите внимание, что запутанный read_csv использует регулярное выражение в качестве разделителя: s означает один или несколько символов пробела, в то время (?!dd:dd:dd) как означает «пропустить этот пробел, если за ним следует что-то вроде 23:55:00». Последнее engine='python' позволяет избежать предупреждений при read_csv() использовании с регулярным выражением