Поиск необычного в группе — что среди планет, что среди меломанов — это прежде всего поиск чемпионов: объектов с выдающимися показателями по разным статьям. Как всю таблицу, так и отдельные группы изучают, сортируя строки по какому-либо столбцу. В Pandas для этой операции есть метод sort_values(). У него два аргумента: • by = 'имя столбца' — имя столбца, по которому нужно сортировать; • ascending: по умолчанию True. Для сортировки по убыванию установите значение False. image Этот аргумент уже знаком вам по аналогичному методу sort() в языке Python. Среди экзопланет интересны близкие по размерам к Земле. Есть ли такие? Отсортируем список по радиусу в порядке возрастания. Тогда в голове таблицы окажутся самые малые, на которых гравитация не прижмёт нас к полу. print(exoplanet.sort_values(by = 'radius').head(30)) NAME MASS RADIUS DISCOVERED 469 Kepler-37 b 0.00875 0.3192 2013 359 Kepler-102 b 0.0013 0.4704 2014 541 Kepler-62 c 0.0126 0.5376 2013 490 Kepler-42 d 0.003 0.5712 2012 390 Kepler-138 b 0.00021 0.5824 2014 360 Kepler-102 c 0.009 0.5824 2013 489 Kepler-42 c 0.006 0.728 2012 470 Kepler-37 c 0.031463 0.749399 2013 552 Kepler-70 b 0.014 0.7616 2011 625 TRAPPIST-1 d 0.0013 0.77168 2016 488 Kepler-42 b 0.009 0.784 2012 481 Kepler-408 b 0.02 0.8176 2013 367 Kepler-106 b 0.00047 0.8176 2014 389 Kepler-131 c 0.026 0.84 2014 346 KIC 12557548 b 6.3e-05 0.849319 2012 479 Kepler-406 c 0.00853 0.8512 2014 417 Kepler-20 e 0.0097 0.86464 2011 553 Kepler-70 c 0.0021 0.8736 2011 363 Kepler-102 f 0.002 0.8848 2013 288 K2-137 b 0.7 0.8848 2017 626 TRAPPIST-1 e 0.002 0.91728 2017 550 Kepler-68 c 0.00686 0.92624 2013 369 Kepler-106 d 0.025 0.952 2014 64 EPIC 248545986 c 0.0028 0.9968 2018 418 Kepler-20 f 0.045 1.00218 2011 627 TRAPPIST-1 f 0.0021 1.04418 2017 624 TRAPPIST-1 c 0.00434 1.05515 2016 350 KOI-2700 b 0.00271 1.05952 2013 623 TRAPPIST-1 b 0.0027 1.08517 2016 534 Kepler-59 b 2.05 1.0976 2012 Оказывается, некоторые из уже открытых экзопланет по размерам близки не то что к Земле, но уже и к Луне! Получим список экзопланет с радиусом меньше земного. Смотрите, как логический оператор (здесь это <) задействуется в отборе элементов столбца. Дальше нам этот приём не раз понадобится. print(exoplanet[exoplanet['radius'] < 1]) NAME MASS RADIUS DISCOVERED 64 EPIC 248545986 c 0.0028 0.9968 2018 288 K2-137 b 0.7 0.8848 2017 346 KIC 12557548 b 6.3e-05 0.849319 2012 359 Kepler-102 b 0.0013 0.4704 2014 360 Kepler-102 c 0.009 0.5824 2013 363 Kepler-102 f 0.002 0.8848 2013 367 Kepler-106 b 0.00047 0.8176 2014 369 Kepler-106 d 0.025 0.952 2014 389 Kepler-131 c 0.026 0.84 2014 390 Kepler-138 b 0.00021 0.5824 2014 417 Kepler-20 e 0.0097 0.86464 2011 469 Kepler-37 b 0.00875 0.3192 2013 470 Kepler-37 c 0.031463 0.749399 2013 479 Kepler-406 c 0.00853 0.8512 2014 481 Kepler-408 b 0.02 0.8176 2013 488 Kepler-42 b 0.009 0.784 2012 489 Kepler-42 c 0.006 0.728 2012 490 Kepler-42 d 0.003 0.5712 2012 541 Kepler-62 c 0.0126 0.5376 2013 550 Kepler-68 c 0.00686 0.92624 2013 552 Kepler-70 b 0.014 0.7616 2011 553 Kepler-70 c 0.0021 0.8736 2011 625 TRAPPIST-1 d 0.0013 0.77168 2016 626 TRAPPIST-1 e 0.002 0.91728 2017 Но и этот список такой длинный, что изучать его лучше по частям. Экзопланеты, близкие по размерам к Земле, за последнее десятилетие открывали нередко. Можно изучать список открытых за каждый год. Например, для 2014 года (вновь обратите внимание на работу логического оператора, теперь это ==): print(exoplanet[exoplanet['discovered'] == 2014]) NAME MASS RADIUS DISCOVERED 83 GU Psc b 11.00000 15.120000 2014 127 HAT-P-49 b 1.73000 15.825600 2014 133 HAT-P-54 b 0.76000 10.572800 2014 150 HATS-15 b 2.17000 12.376000 2014 175 HATS-4 b 1.32300 11.424000 2014 183 HATS-5 b 0.23700 10.214400 2014 194 HATS-6 b 0.31900 11.177600 2014 213 HD 114613 b 0.35700 13.238400 2014 274 HIP 116454 b 0.03720 2.531200 2014 347 KOI-188 b 0.25000 10.953600 2014 348 KOI-192 b 0.29000 13.776000 2014 349 KOI-195 b 0.34000 12.208000 2014 352 KOI-830 b 1.27000 12.096000 2014 356 Kepler-100 b 0.02310 1.303680 2014 357 Kepler-100 c 0.00270 2.218720 2014 358 Kepler-100 d 0.00940 1.513120 2014 359 Kepler-102 b 0.00130 0.470400 2014 361 Kepler-102 d 0.00820 1.164800 2014 364 Kepler-103 b 0.03100 3.473120 2014 365 Kepler-103 c 0.11400 5.314400 2014 366 Kepler-105 c 0.01400 1.310400 2014 367 Kepler-106 b 0.00047 0.817600 2014 368 Kepler-106 c 0.03285 2.497600 2014 369 Kepler-106 d 0.02500 0.952000 2014 370 Kepler-106 e 0.03514 2.553600 2014 371 Kepler-109 b 0.00410 2.336320 2014 372 Kepler-109 c 0.00698 2.632000 2014 379 Kepler-113 b 0.03680 1.814400 2014 380 Kepler-113 c 0.02700 2.172800 2014 388 Kepler-131 b 0.05075 2.408000 2014 ... ... ... ... ... 480 Kepler-407 b 0.01000 1.163680 2014 484 Kepler-412 b 0.93900 14.840000 2014 486 Kepler-418 b 1.10000 13.440000 2014 491 Kepler-420 A b 1.45000 10.528000 2014 492 Kepler-422 b 0.43000 12.880000 2014 493 Kepler-423 b 0.59500 13.350400 2014 494 Kepler-424 b 1.03000 9.968000 2014 496 Kepler-432 b 5.41000 16.240000 2014 510 Kepler-453 (AB) b 0.03000 6.160000 2014 515 Kepler-48 d 0.02500 2.038400 2014 522 Kepler-51 d 0.02390 9.688000 2014 583 Kepler-93 b 0.01260 1.481812 2014 584 Kepler-94 b 0.03411 3.505600 2014 585 Kepler-95 b 0.04100 3.416000 2014 586 Kepler-96 b 0.02700 2.665600 2014 641 WASP-103 b 1.49000 17.113600 2014 642 WASP-104 b 1.27200 12.734400 2014 644 WASP-106 b 1.92500 12.152000 2014 646 WASP-108 b 1.16700 13.608000 2014 647 WASP-109 b 0.91000 16.161600 2014 648 WASP-110 b 0.51500 13.865600 2014 649 WASP-111 b 1.85000 16.150400 2014 650 WASP-112 b 0.88000 13.339200 2014 653 WASP-117 b 0.27550 11.435200 2014 768 WASP-74 b 0.97000 17.472000 2014 778 WASP-83 b 0.30000 11.648000 2014 780 WASP-85 A b 1.26500 13.888000 2014 782 WASP-87 A b 2.21000 15.512000 2014 784 WASP-89 b 5.90000 11.648000 2014 789 WASP-94 A b 0.45200 19.264000 2014 А чтобы не тратить время на лишнее, поставим оба условия сразу. Для этого в Pandas есть логический оператор &, подобный оператору and языка Python. Напомним, его смысл на русском языке можно передать словами «и ещё»: # экзопланеты меньше Земли __ и ещё __ открытые в 2014 году exo_small_14 = exoplanet[ (exoplanet['radius']<1) & (exoplanet['discovered']==2014)] print(exo_small_14) NAME MASS RADIUS DISCOVERED 359 Kepler-102 b 0.00130 0.4704 2014 367 Kepler-106 b 0.00047 0.8176 2014 369 Kepler-106 d 0.02500 0.9520 2014 389 Kepler-131 c 0.02600 0.8400 2014 390 Kepler-138 b 0.00021 0.5824 2014 479 Kepler-406 c 0.00853 0.8512 2014 Отсортируем результат в порядке убывания радиуса. print(exo_small_14.sort_values(by = 'radius', ascending = False)) NAME MASS RADIUS DISCOVERED 369 Kepler-106 d 0.025 0.952 2014 479 Kepler-406 c 0.00853 0.8512 2014 389 Kepler-131 c 0.026 0.84 2014 367 Kepler-106 b 0.00047 0.8176 2014 390 Kepler-138 b 0.00021 0.5824 2014 359 Kepler-102 b 0.0013 0.4704 2014 Самая крупная планета, Kepler 106 d – почти как Земля, вращается вокруг звезды Kepler 106 в созвездии Лебедя. Эта звезда очень похожа на наше Солнце. Правда, до неё 1435 световых лет — далековато. Но, возможно, учёные что-нибудь придумают. А мы пока применим эту технологию к нашему бизнесу, в «приземлённой» задаче. TASK_1_5 Космический телескоп Kepler открыл похожую на Землю планету у похожей на Солнце звезды. А вы в данных Яндекс.Музыки обнаружили меломана с уникальными данными. Он за день послушал больше 50 композиций. Получите таблицу с прослушанными им треками. Для этого запросите из структуры данных df строки, отвечающие сразу двум условиям: 1) значение в столбце 'user_id' должно быть равно значению переменной search_id; 2) время прослушивания, т.е. значение в столбце 'total_play_seconds', не должно равняться 0. Сохраните результат в переменной music_user. SOLUTION import pandas as pd df = pd.read_csv('music_log_upd.csv') genre_grouping = df.groupby('user_id')['genre_name'] def user_genres(group): for col in group: if len(col[1]) > 50: user = col[0] return user search_id = user_genres(genre_grouping) music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] print(music_user) TASK_2_5 Теперь узнаем, сколько времени он слушал музыку каждого жанра. Сгруппируйте данные таблицы music_user по столбцу 'genre_name' и получите сумму значений столбца 'total_play_seconds'. Сохраните результат в переменной sum_music_user и выведите её значение на экран. SOLUTION import pandas as pd df = pd.read_csv('music_log_upd.csv') genre_grouping = df.groupby('user_id')['genre_name'] def user_genres(group): for col in group: if len(col[1]) > 50: user = col[0] return user search_id = user_genres(genre_grouping) music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] #print(music_user) sum_music_user=music_user.groupby("genre_name")['total_play_seconds'].sum() print(sum_music_user) TASK_3_5 Кажется, предпочтения нашего меломана начинают проявляться. Но, возможно, длительность композиций от жанра к жанру сильно различается. Важно знать, сколько треков каждого жанра он включил. Сгруппируйте данные по столбцу genre_name и посчитайте, сколько значений в столбце genre_name. Сохраните результат в переменной count_music_user и выведите её значение на экран. Чтобы команда «распечатать сумму» из прошлой задачи не мешала рассматривать новое решение, закомментируйте её. SOLUTION import pandas as pd df = pd.read_csv('music_log_upd.csv') genre_grouping = df.groupby('user_id')['genre_name'] def user_genres(group): for col in group: if len(col[1]) > 50: user = col[0] return user search_id = user_genres(genre_grouping) music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] #print(music_user) sum_music_user=music_user.groupby("genre_name")['total_play_seconds'].sum() #print(sum_music_user) count_music_user=music_user.groupby("genre_name")['genre_name'].count() print(count_music_user) TASK_4_5 Чтобы предпочтения были видны сразу, нужно крупнейшие значения расположить наверху. Отсортируйте данные в группировке sum_music_user по убыванию. Внимание: когда применяете метод sort_values() к Series с единственным столбцом, аргумент by указывать не нужно, только порядок сортировки. Сохраните результат в переменной final_sum и выведите её значение на экран. Команду «распечатать сумму» из прошлой задачи закомментируйте. SOLUTION import pandas as pd df = pd.read_csv('music_log_upd.csv') genre_grouping = df.groupby('user_id')['genre_name'] def user_genres(group): for col in group: if len(col[1]) > 50: user = col[0] return user search_id = user_genres(genre_grouping) music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] #print(music_user) sum_music_user=music_user.groupby("genre_name")['total_play_seconds'].sum() #print(sum_music_user) count_music_user=music_user.groupby("genre_name")['genre_name'].count() #print(count_music_user) final_sum=sum_music_user.sort_values(ascending=False) print(final_sum) TASK_5_5 Теперь то же самое надо сделать с числом прослушанных меломаном композиций. Отсортируйте данные группировки count_music_user по убыванию. Сохраните результат в переменной final_count, значение которой выведите на экран. Команду «распечатать» из прошлой задачи закомментируйте. SOLUTION import pandas as pd df = pd.read_csv('music_log_upd.csv') genre_grouping = df.groupby('user_id')['genre_name'] def user_genres(group): for col in group: if len(col[1]) > 50: user = col[0] return user search_id = user_genres(genre_grouping) music_user=df[(df['user_id']==search_id)&(df["total_play_seconds"]!=0)] #print(music_user) sum_music_user=music_user.groupby("genre_name")['total_play_seconds'].sum() #print(sum_music_user) count_music_user=music_user.groupby("genre_name")['genre_name'].count() #print(count_music_user) final_sum=sum_music_user.sort_values(ascending=False) #print(final_sum) final_count=count_music_user.sort_values(ascending=False) print(final_count)