Как сопоставить несколько элементов из списка с одним элементом из другого списка?

#python #list #date #plot #items

#python #Список #Дата #график #Товары

Вопрос:

Мне нужно сопоставить элементы из списка array (364 элемента) со списком months (12 элементов). Будет несколько элементов array , соответствующих каждому месяцу months .

 array = ['309', '307', '303', '296', '322', '340', '321', '314', '327', '315', '316', '333', '296', '286', '289', '290', '316', '317', '333', '348', '398', '396', '404', '424', '402', '357', '320', '315', '321', '328', '312', '293', '302', '296', '286', '281', '281', '  0', '312', '326', '332', '293', '242', '259', '268', '316', '296', '303', '280', '308', '314', '298', '307', '303', '300', '284', '289', '337', '308', '300', '288', '333', '321', '373', '301', '272', '288', '322', '318', '314', '321', '297', '299', '306', '312', '325', '334', '390', '339', '317', '343', '336', '357', '366', '383', '379', '355', '342', '369', '362', '359', '360', '380', '388', '393', '362', '347', '335', '322', '334', '313', '309', '303', '304', '326', '354', '364', '360', '343', '335', '343', '366', '318', '347', '326', '327', '329', '334', '347', '364', '346', '338', '337', '325', '304', '285', '298', '310', '316', '311', '321', '323', '360', '351', '337', '345', '372', '367', '356', '331', '308', '323', '327', '312', '300', '296', '305', '323', '338', '328', '319', '315', '315', '313', '316', '314', '312', '354', '317', '323', '324', '352', '360', '342', '333', '348', '335', '320', '321', '326', '327', '323', '303', '318', '308', '307', '302', '293', '304', '322', '302', '307', '304', '302', '287', '290', '306', '299', '297', '284', '289', '287', '316', '292', '291', '307', '300', '318', '302', '309', '320', '296', '293', '291', '287', '293', '287', '296', '293', '297', '287', '296', '296', '290', '287', '290', '290', '302', '298', '301', '297', '302', '290', '297', '288', '288', '299', '319', '311', '300', '302', '305', '294', '293', '288', '288', '289', '291', '286', '282', '280', '287', '279', '294', '345', '344', '292', '317', '296', '287', '288', '285', '291', '300', '298', '288', '288', '287', '275', '282', '288', '270', '272', '283', '284', '284', '295', '290', '279', '290', '287', '276', '289', '286', '295', '301', '287', '332', '305', '304', '275', '263', '266', '256', '257', '269', '258', '257', '273', '291', '277', '272', '280', '266', '269', '256', '282', '274', '308', '295', '288', '331', '290', '295', '283', '288', '285', '267', '274', '279', '300', '290', '293', '308', '285', '288', '279', '270', '281', '297', '296', '275', '255', '242', '239', '242', '269', '275', '278', '286', '276', '269', '283', '290', '317', '286', '287', '282', '273', '289', '322', '352', '268', '290', '311', '277', '256', '246', '255', '252', '265', '269', '265', '278', '272', '273', '302', '287', '284', '316', '318', '310', '280', '288', '293', '291'] 

months=['January 2020', 'February 2020', 'March 2020', 'April 2020', 'May 2020', 'June 2020', 'July 2020', 'August 2020', 'September 2020', 'October 2020', 'November 2020', 'December 2020'] 
 

364 значения в array соответствуют данным по озону за каждый день за последний 2020 год, поэтому мне нужно сопоставить каждый 31 (или 30, даже 29 в случае февраля и декабря) элементов с правильным месяцем, учитывая, что первое значение в «массиве» соответствует дате 01-01-2020 ипоследнее значение соответствует 29-12-2020. Я действительно не знаю, есть ли команда или мне нужно напрямую выполнять это с помощью кода.

Моя конечная цель кода — построить график months по оси x и array по оси y с помощью любых библиотек, таких как matplotlib:

 import matplotlib.pyplot as plt 

plt.plot(months, array)
plt.ylabel('Ozone Madrid') 
plt.xlabel('Months') 
plt.show() 
 

В настоящее время я не могу отобразить это, потому что аргументы (два списка), которые принимают plt.plot() , не имеют одинакового количества элементов. Вот почему я подумал об этом предыдущем шаге.

Есть ли другие способы сделать это быстрее и эффективнее?

Ответ №1:

Вы можете использовать monthrange функцию из calendar (встроенную), чтобы получить количество дней в месяце. Ваш код будет примерно таким

 from calendar import monthrange

month_vals = []

for i in range(1, 13):
    vals = array[:monthrange(2020, i)[1]]
    array = array[monthrange(2020, i)[1]:]
    month_vals.append(vals)
 

ПРИМЕЧАНИЕ: array у вас 366 значений, а не 364

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

1. Моя ошибка, спасибо, что заметили это! Я не проверял это перед публикацией… это потому, что после того, как я скопировал список сюда, я отредактировал файл, из которого я получаю данные ozone (на самом деле я только что удалил 2 файла, которые соответствовали 2 дополнительным элементам, которые я наконец опубликовал). Что касается кода, я попытаюсь использовать ‘monthrange’, но мне не нужно вычислять среднее значение каждого месяца, мне нужны все эти значения, но сгруппированные по месяцам, чтобы отобразить их

2. В этом случае я обновлю ответ. Но я не думаю plt.plot(months, array) , что это будет так, как вы хотите. Возможно, вам потребуется немного больше изучить matplotlib , чтобы сделать это

Ответ №2:

Хорошо, итак, другой парень из сообщения Spanish Stack Overflow (все кредиты пользователю: Рубиалес Альберто) дал мне ключ, поэтому я публикую его здесь, если это полезно для кого-то еще.

Хотя мне все равно нужно иметь одинаковое количество аргументов как months в, так и array in order to plot it, we can create the months list by using в библиотеке pandas. Вот код:

Ввод

 import pandas as pd
import matplotlib.pyplot as plt

array = ['309', '307', '303', '296', '322', '340', '321', '314', '327', '315', '316', '333', '296', '286', '289', '290', '316', '317', '333', '348', '398', '396', '404', '424', '402', '357', '320', '315', '321', '328', '312', '293', '302', '296', '286', '281', '281', '  0', '312', '326', '332', '293', '242', '259', '268', '316', '296', '303', '280', '308', '314', '298', '307', '303', '300', '284', '289', '337', '308', '300', '288', '333', '321', '373', '301', '272', '288', '322', '318', '314', '321', '297', '299', '306', '312', '325', '334', '390', '339', '317', '343', '336', '357', '366', '383', '379', '355', '342', '369', '362', '359', '360', '380', '388', '393', '362', '347', '335', '322', '334', '313', '309', '303', '304', '326', '354', '364', '360', '343', '335', '343', '366', '318', '347', '326', '327', '329', '334', '347', '364', '346', '338', '337', '325', '304', '285', '298', '310', '316', '311', '321', '323', '360', '351', '337', '345', '372', '367', '356', '331', '308', '323', '327', '312', '300', '296', '305', '323', '338', '328', '319', '315', '315', '313', '316', '314', '312', '354', '317', '323', '324', '352', '360', '342', '333', '348', '335', '320', '321', '326', '327', '323', '303', '318', '308', '307', '302', '293', '304', '322', '302', '307', '304', '302', '287', '290', '306', '299', '297', '284', '289', '287', '316', '292', '291', '307', '300', '318', '302', '309', '320', '296', '293', '291', '287', '293', '287', '296', '293', '297', '287', '296', '296', '290', '287', '290', '290', '302', '298', '301', '297', '302', '290', '297', '288', '288', '299', '319', '311', '300', '302', '305', '294', '293', '288', '288', '289', '291', '286', '282', '280', '287', '279', '294', '345', '344', '292', '317', '296', '287', '288', '285', '291', '300', '298', '288', '288', '287', '275', '282', '288', '270', '272', '283', '284', '284', '295', '290', '279', '290', '287', '276', '289', '286', '295', '301', '287', '332', '305', '304', '275', '263', '266', '256', '257', '269', '258', '257', '273', '291', '277', '272', '280', '266', '269', '256', '282', '274', '308', '295', '288', '331', '290', '295', '283', '288', '285', '267', '274', '279', '300', '290', '293', '308', '285', '288', '279', '270', '281', '297', '296', '275', '255', '242', '239', '242', '269', '275', '278', '286', '276', '269', '283', '290', '317', '286', '287', '282', '273', '289', '322', '352', '268', '290', '311', '277', '256', '246', '255', '252', '265', '269', '265', '278', '272', '273', '302', '287', '284', '316', '318', '310', '280', '288', '293', '291']

#The numbers of the list are string type, so we transform them into integers:
array = [int(n) for n in array]

#We create a list of months, this is the important command-line:
months = pd.date_range("01-01-2020", "31-12-2020")


plt.plot(months, array)
plt.ylabel('Ozone Madrid')
plt.xlabel('Months')
plt.show()
 

Вывод

 # (It doesn't allow me to upload images yet cause I'm a beginner here, 
# but it gives me the linear graph that I needed)
 

В любом случае, я не совсем уверен, почему, используя pd.date_range("date1", "date2") from pandas library to plot, автоматически настраивайте данные на такой график вместо других опций, которые люди разместили мне здесь, но поскольку pandas он был закодирован для анализа данных, следующее, что я сделаю, это прочитать его документацию.

Большое спасибо за вашу помощь

Ответ №3:

Вы можете найти месяц дня на основе его положения в году:

 from datetime import date
def get_month_from_yday(year, yday):
    '''
        year is the reference year
        yday is the day's position in the year (0 is January 1st etc.)
    '''
    return date.fromordinal(date(year,1,1).toordinal()   yday).strftime("%B %Y")
 

Ввод

 # Month if the 1st day of the year
print(get_month_from_yday(2020, 0))

# Month if the 32nd day of the year
print(get_month_from_yday(2020, 31))

# Month if the 361st day of the year
print(get_month_from_yday(2020, 360))
 

Вывод

 January 2020
February 2020
December 2020
 

С помощью этой функции вы можете получить номер дня месяца на основе индекса вашего массива.

Отображение графика

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

 from datetime import date
import matplotlib.pyplot as plt 
fig, ax = plt.subplots()

def get_month_from_yday(year, yday):
    '''
        year is the reference year
        yday is the day's position in the year (0 is January 1st etc.)
    '''
    return date.fromordinal(date(year,1,1).toordinal()   yday).strftime("%B %Y")

# Input value
array = ['309', '307', '303', '296', '322', '340', '321', '314', '327', '315', '316', '333', '296', '286', '289', '290', '316', '317', '333', '348', '398', '396', '404', '424', '402', '357', '320', '315', '321', '328', '312', '293', '302', '296', '286', '281', '281', '  0', '312', '326', '332', '293', '242', '259', '268', '316', '296', '303', '280', '308', '314', '298', '307', '303', '300', '284', '289', '337', '308', '300', '288', '333', '321', '373', '301', '272', '288', '322', '318', '314', '321', '297', '299', '306', '312', '325', '334', '390', '339', '317', '343', '336', '357', '366', '383', '379', '355', '342', '369', '362', '359', '360', '380', '388', '393', '362', '347', '335', '322', '334', '313', '309', '303', '304', '326', '354', '364', '360', '343', '335', '343', '366', '318', '347', '326', '327', '329', '334', '347', '364', '346', '338', '337', '325', '304', '285', '298', '310', '316', '311', '321', '323', '360', '351', '337', '345', '372', '367', '356', '331', '308', '323', '327', '312', '300', '296', '305', '323', '338', '328', '319', '315', '315', '313', '316', '314', '312', '354', '317', '323', '324', '352', '360', '342', '333', '348', '335', '320', '321', '326', '327', '323', '303', '318', '308', '307', '302', '293', '304', '322', '302', '307', '304', '302', '287', '290', '306', '299', '297', '284', '289', '287', '316', '292', '291', '307', '300', '318', '302', '309', '320', '296', '293', '291', '287', '293', '287', '296', '293', '297', '287', '296', '296', '290', '287', '290', '290', '302', '298', '301', '297', '302', '290', '297', '288', '288', '299', '319', '311', '300', '302', '305', '294', '293', '288', '288', '289', '291', '286', '282', '280', '287', '279', '294', '345', '344', '292', '317', '296', '287', '288', '285', '291', '300', '298', '288', '288', '287', '275', '282', '288', '270', '272', '283', '284', '284', '295', '290', '279', '290', '287', '276', '289', '286', '295', '301', '287', '332', '305', '304', '275', '263', '266', '256', '257', '269', '258', '257', '273', '291', '277', '272', '280', '266', '269', '256', '282', '274', '308', '295', '288', '331', '290', '295', '283', '288', '285', '267', '274', '279', '300', '290', '293', '308', '285', '288', '279', '270', '281', '297', '296', '275', '255', '242', '239', '242', '269', '275', '278', '286', '276', '269', '283', '290', '317', '286', '287', '282', '273', '289', '322', '352', '268', '290', '311', '277', '256', '246', '255', '252', '265', '269', '265', '278', '272', '273', '302', '287', '284', '316', '318', '310', '280', '288', '293', '291'] 
months=['January 2020', 'February 2020', 'March 2020', 'April 2020', 'May 2020', 'June 2020', 'July 2020', 'August 2020', 'September 2020', 'October 2020', 'November 2020', 'December 2020'] 

# List of months for each of the array values
data_month = [get_month_from_yday(2020, i) for i in range(len(array))]
# List of array values as integer
y_values = [int(x) for x in array]

# List containing the index of the months starts
month_starts_index = [i for i in range(len(data_month)) if i==0 or (i!=0 and data_month[i-1] != data_month[i]) or i == len(data_month)-1]

# Draw a vertical span of different color for each month
colors=['red','blue']
for i in range(len(month_starts_index)):
    if i!=0:
        ax.axvspan(month_starts_index[i-1], month_starts_index[i], color=colors[i%len(colors)], alpha=0.3)

# Display a tick on the x-axis at each month start
plt.xticks(month_starts_index, [month for i, month in enumerate(data_month) if i in month_starts_index], rotation=45)

plt.xlabel('Months') 
plt.ylabel('Ozone Madrid')
plt.xlim(0, len(y_values)-1)
plt.plot(range(len(y_values)), y_values)
plt.show() 
 

Результат
введите описание изображения здесь

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

1. Спасибо за быстрый ответ, Марк, о вашем коде, я все еще не понимаю, как я могу использовать его для своей проблемы… Как я могу использовать команды ‘datetime’, если они принимают даты (а не индекс массива) в качестве аргументов ?… Я ошибаюсь?

2. Добро пожаловать. Я отредактировал свой ответ, чтобы привести пример того, как вы можете отобразить значения, сгруппированные по месяцам.

3. Еще раз спасибо, это было действительно полезно!! Я кодировал его прямо сейчас, а потом увидел ваш ответ, вы сэкономили мне немного времени… И последний вопрос: как я могу отобразить те же результаты с помощью линейной графики вместо столбцов??? Мне все еще нужно лучше проверить документацию matplotlib, чтобы лучше изучить командные строки, поэтому, если вы это знаете, я буду вечно благодарен (как вы можете видеть, я очень новичок)

4. Добро пожаловать 🙂 Я не уверен в том, каким образом вы хотите отобразить данные. Если вы хотите построить классический линейный график, зачем вам группировать данные по месяцам?

5. Мне нужен линейный график, чтобы показать эволюцию ozone, зависящую от времени (у меня есть ежедневные значения, но я не могу отобразить его с указанием дней по оси x, потому что их слишком много). Следующий шаг — изменить его на частотно-зависимый с помощью преобразования Фурье. Наличие обоих в линейном формате поможет мне лучше изучить и сравнить результаты эволюции ozone среди нескольких графиков. В любом случае, я думаю, что это решено, я только что опубликовал ответ, чтобы любой мог его прочитать. Тем не менее: большое спасибо за вашу помощь, Марк 🙂