Pandas DataFrames

Огляд

Викладання: 15 хв
Вправи: 15 хв
Питання
  • Як я можу зробити статистичний аналіз табличних даних?

Цілі
  • Вибір окремих значень з фрейму даних Pandas.

  • Вибір цілих рядків або цілих стовпців з фрейму даних.

  • Вибір підмножини рядків і стовпців з фрейму даних за одну операцію.

  • Вибір підмножини фрейму даних за одним бульовим критерієм.

Зауваження щодо Pandas DataFrames/Series

DataFrame є колекцією Series; DataFrame — це спосіб, у який Pandas представляє таблицю, а Series — це структура даних, яку Pandas використовує для представлення стовпця.

Pandas побудована на основі бібліотеки Numpy, що на практиці означає, що більшість методів, визначених для Numpy Arrays, застосовуються до Pandas Series/DataFrames.

Що робить Pandas таким привабливим? Це потужний інтерфейс для доступу до окремих записів таблиці, належна обробка відсутніх значень і операції з з фреймами даних подібно до тих, що застосовуються в реляційних базах даних.

Вибір значень

Щоб отримати доступ до значення в позиції [i,j] у DataFrame, у нас є два варіанти, залежно від того, в якому значенні використовується i. Пам’ятайте, що DataFrame використовує індекс як спосіб ідентифікації рядків таблиці; крім того, рядок має позицію всередині таблиці, а також мітку, яка унікально ідентифікує введення значення у DataFrame.

Використовуйте DataFrame.iloc[..., ...] для вибору значень за їх позицією

import pandas as pd
data = pd.read_csv('data/gapminder_gdp_europe.csv', index_col='country')
print(data.iloc[0, 0])
1601.056136

Використовуйте DataFrame.loc[..., ...], щоб вибрати значення за їх міткою.

data = pd.read_csv('data/gapminder_gdp_europe.csv', index_col='country')
print(data.loc["Albania", "gdpPercap_1952"])
1601.056136

Використовуйте : окремо для позначення всіх стовпців або всіх рядків.

print(data.loc["Albania", :])
gdpPercap_1952    1601.056136
gdpPercap_1957    1942.284244
gdpPercap_1962    2312.888958
gdpPercap_1967    2760.196931
gdpPercap_1972    3313.422188
gdpPercap_1977    3533.003910
gdpPercap_1982    3630.880722
gdpPercap_1987    3738.932735
gdpPercap_1992    2497.437901
gdpPercap_1997    3193.054604
gdpPercap_2002    4604.211737
gdpPercap_2007    5937.029526
Name: Albania, dtype: float64
print(data.loc[:, "gdpPercap_1952"])
country
Albania                    1601.056136
Austria                    6137.076492
Belgium                    8343.105127
⋮ ⋮ ⋮
Switzerland               14734.232750
Turkey                     1969.100980
United Kingdom             9979.508487
Name: gdpPercap_1952, dtype: float64

Вибирайте кілька стовпців або рядків за допомогою DataFrame.loc та визначеного зрізу.

print(data.loc['Italy':'Poland', 'gdpPercap_1962':'gdpPercap_1972'])
             gdpPercap_1962  gdpPercap_1967  gdpPercap_1972
country
Italy           8243.582340    10022.401310    12269.273780
Montenegro      4649.593785     5907.850937     7778.414017
Netherlands    12790.849560    15363.251360    18794.745670
Norway         13450.401510    16361.876470    18965.055510
Poland          5338.752143     6557.152776     8006.506993

У наведеному вище коді ми бачимо, що зріз із застосуванням loc включає обидва виміри, що відрізняється від зрізу із застосуванням iloc, де зріз включає все, крім кінцевого індексу.

Результат застосування операції зрізу може бути використаний у подальших операціях.

print(data.loc['Italy':'Poland', 'gdpPercap_1962':'gdpPercap_1972'].max())
gdpPercap_1962    13450.40151
gdpPercap_1967    16361.87647
gdpPercap_1972    18965.05551
dtype: float64
print(data.loc['Italy':'Poland', 'gdpPercap_1962':'gdpPercap_1972'].min())
gdpPercap_1962    4649.593785
gdpPercap_1967    5907.850937
gdpPercap_1972    7778.414017
dtype: float64

Використовуйте порівняння для вибору даних на основі певного значення.

# Використовуйте підмножину даних, щоб результат був читабельним.
subset = data.loc['Italy':'Poland', 'gdpPercap_1962':'gdpPercap_1972']
print('Підмножина даних:\
', subset)

# Які значення були більшими за 10000?
print('\
Які значення більші?\
', subset > 10000)
~~~{: .language-python}

Підмножина даних: gdpPercap_1962 gdpPercap_1967 gdpPercap_1972 country Italy 8243.582340 10022.401310 12269.273780 Montenegro 4649.593785 5907.850937 7778.414017 Netherlands 12790.849560 15363.251360 18794.745670 Norway 13450.401510 16361.876470 18965.055510 Poland 5338.752143 6557.152776 8006.506993

Які значення більші? gdpPercap_1962 gdpPercap_1967 gdpPercap_1972 country Italy False True True Montenegro False False False Netherlands True True True Norway True True True Poland False False False

{: .output}

## Виберіть значення або NaN за допомогою булевої маски.

*   Фрейм, повний булевих значень, іноді називають *маскою* через спосіб його використання.

mask = subset > 10000 print(subset[mask])

{: .language-python}
         gdpPercap_1962  gdpPercap_1967  gdpPercap_1972 country Italy                   NaN     10022.40131     12269.27378 Montenegro              NaN             NaN             NaN Netherlands     12790.84956     15363.25136     18794.74567 Norway          13450.40151     16361.87647     18965.05551 Poland                  NaN             NaN             NaN ~~~
print(subset[subset > 10000].describe())
       gdpPercap_1962  gdpPercap_1967  gdpPercap_1972
count        2.000000        3.000000        3.000000
mean     13120.625535    13915.843047    16676.358320
std        466.373656     3408.589070     3817.597015
min      12790.849560    10022.401310    12269.273780
25%      12955.737547    12692.826335    15532.009725
50%      13120.625535    15363.251360    18794.745670
75%      13285.513523    15862.563915    18879.900590
max      13450.401510    16361.876470    18965.055510

Групувати за: розділити-застосувати-комбінувати

Методи векторизації та операції групування Pandas — це функції, які надають користувачам велику гнучкість для аналізу своїх даних.

Наприклад, скажімо, ми хочемо мати більш чітке уявлення про те, як європейські країни розподілені відповідно до свого ВВП.

  1. Ми можемо поглянути, розділивши країни на дві групи протягом досліджуваних років, на тих, у кого ВВП вищий за середній європейський, та тих, у кого ВВП нижчий.
  2. Потім ми оцінюємо показник заможності на основі історичних значень (з 1962 по 2007 рік), де ми враховуємо, скільки разів країна була у групах з нижчим або вищим ВВП
mask_higher = data > data.mean()
wealth_score = mask_higher.aggregate('sum', axis=1) / len(data.columns)
wealth_score
country
Albania                   0.000000
Austria                   1.000000
Belgium                   1.000000
Bosnia and Herzegovina    0.000000
Bulgaria                  0.000000
Croatia                   0.000000
Czech Republic            0.500000
Denmark                   1.000000
Finland                   1.000000
France                    1.000000
Germany                   1.000000
Greece                    0.333333
Hungary                   0.000000
Iceland                   1.000000
Ireland                   0.333333
Italy                     0.500000
Montenegro                0.000000
Netherlands               1.000000
Norway                    1.000000
Poland                    0.000000
Portugal                  0.000000
Romania                   0.000000
Serbia                    0.000000
Slovak Republic           0.000000
Slovenia                  0.333333
Spain                     0.333333
Sweden                    1.000000
Switzerland               1.000000
Turkey                    0.000000
United Kingdom            1.000000
dtype: float64

Нарешті, для кожної групи в таблиці wealth_score ми підсумовуємо їх (фінансовий) внесок за роки дослідження:

data.groupby(wealth_score).sum()
          gdpPercap_1952  gdpPercap_1957  gdpPercap_1962  gdpPercap_1967  \
0.000000    36916.854200    46110.918793    56850.065437    71324.848786   
0.333333    16790.046878    20942.456800    25744.935321    33567.667670   
0.500000    11807.544405    14505.000150    18380.449470    21421.846200   
1.000000   104317.277560   127332.008735   149989.154201   178000.350040   

          gdpPercap_1972  gdpPercap_1977  gdpPercap_1982  gdpPercap_1987  \
0.000000    88569.346898   104459.358438   113553.768507   119649.599409   
0.333333    45277.839976    53860.456750    59679.634020    64436.912960   
0.500000    25377.727380    29056.145370    31914.712050    35517.678220   
1.000000   215162.343140   241143.412730   263388.781960   296825.131210   

          gdpPercap_1992  gdpPercap_1997  gdpPercap_2002  gdpPercap_2007  
0.000000    92380.047256   103772.937598   118590.929863   149577.357928  
0.333333    67918.093220    80876.051580   102086.795210   122803.729520  
0.500000    36310.666080    40723.538700    45564.308390    51403.028210  
1.000000   315238.235970   346930.926170   385109.939210   427850.333420

Вибір індивідуальних значень

Припустімо, Pandas було імпортовано у ваш блокнот і дані Gapminder про ВВП Європи завантажено:

import pandas as pd

df = pd.read_csv('data/gapminder_gdp_europe.csv', index_col='country')

Напишіть вираз для визначення ВВП на душу населення в Сербії у 2007 році.

Рішення

Вибір можна зробити за допомогою міток як для рядка (“Serbia”), так і для стовпця (“gdpPercap_2007”):

print(df.loc['Serbia', 'gdpPercap_2007'])

Результат

9786.534714

Ступінь зріза

  1. Чи дають два наведені нижче твердження однаковий результат?
  2. Виходячи з цього, яке правило керує тим, що включено (чи ні) до числових і іменованих зрізів у Pandas?
print(df.iloc[0:2, 0:2])
print(df.loc['Albania':'Belgium', 'gdpPercap_1952':'gdpPercap_1962'])

Рішення

Ні, вони не дають однакові результати! Результатом першого виразу є:

        gdpPercap_1952  gdpPercap_1957
country                                
Albania     1601.056136     1942.284244
Austria     6137.076492     8842.598030

Друге твердження дає:

        gdpPercap_1952  gdpPercap_1957  gdpPercap_1962
country                                                
Albania     1601.056136     1942.284244     2312.888958
Austria     6137.076492     8842.598030    10750.721110
Belgium     8343.105127     9714.960623    10991.206760

Очевидно, що другий оператор створює додатковий стовпець і додатковий рядок порівняно з першим оператором. Який висновок ми можемо зробити? Ми бачимо, що числовий зріз 0:2 опускає остаточний індекс (тобто індекс 2) в наданому діапазоні, тоді як іменований зріз, ‘gdpPercap_1952’:’gdpPercap_1962’, включає останній елемент.

Реконструювання даних

Поясніть, що робить кожен рядок у наступній короткій програмі: що в first, second, etc.?

first = pd.read_csv('data/gapminder_all.csv', index_col='country')
second = first[first['continent'] == 'Americas']
third = second.drop('Puerto Rico')
fourth = third.drop('continent', axis = 1)
fourth.to_csv('result.csv')

Рішення

Давайте переглянемо цей фрагмент коду рядок за рядком.

first = pd.read_csv('data/gapminder_all.csv', index_col='country')

Цей рядок завантажує набір даних, що містить дані про ВВП усіх країн, у фрейм даних під назвою first. Параметр index_col='country' вибирає, який стовпець використовувати як мітки рядків у фреймі даних.

second = first[first['continent'] == 'Americas']

Цей рядок забезпечує вибір: лише ті рядки first, для яких стовпець ‘continent’ відповідає значенню ‘Americas’. Зверніть увагу, як логічний вираз у дужках, first['continent'] == 'Americas', використовується для вибору лише тих рядків, де вираз є істинним. Спробуйте надрукувати цей вираз! Чи можете ви також надрукувати його окремі елементи True/False? (підказка: спочатку призначте вираз змінній)

third = second.drop('Puerto Rico')

Як підказує синтаксис, цей вираз вилучає рядок із second з міткою ‘Пуерто-Ріко’. Отриманий фрейм даних third має на один рядок менше, ніж вихідний фрейм даних second.

fourth = third.drop('continent', axis = 1)

Ми знову застосовуємо функцію drop, але в цьому випадку ми видаляємо не рядок, а цілий стовпець. Щоб виконати це, нам також потрібно вказати параметр axis (ми хочемо відкинути другий стовпець який має індекс 1).

fourth.to_csv('result.csv')

Останнім кроком є ​​запис даних, над якими ми працювали, у файл CSV. Panda робить це легко
за допомогою функції to_csv() . Єдиним обов’язковим аргументом для функції є ім’я файлу. Зверніть увагу, що файл буде записано в каталозі, з якого ви розпочали сеанс Jupyter або Python.

Вибір індексів

Поясніть простими словами, що роблять idxmin і idxmax у короткій програмі нижче. Коли б ви використовували ці методи?

data = pd.read_csv('data/gapminder_gdp_europe.csv', index_col='country')
print(data.idxmin())
print(data.idxmax())

Рішення

Для кожного стовпця в data idxmin поверне значення індексу, що відповідає мінімуму кожного стовпця; idxmax зробить те саме для максимального значення кожного стовпця.

Ви можете використовувати ці функції щоразу, коли хочете отримати індекс рядка мінімального/максимального значення, а не фактичне мінімальне/максимальне значення.

Практика з вибором

Припустімо, що Pandas було імпортовано та дані Gapminder про ВВП для Європи завантажено. Напишіть вираз, щоб вибрати кожне з наступного:

  1. ВВП на душу населення для всіх країн у 1982р.
  2. ВВП на душу населення для Данії за всі роки.
  3. ВВП на душу населення для всіх країн за роки після 1985.
  4. ВВП на душу населення для кожної країни у 2007 р. як кратне ВВП на душу населення для цієї країни в 1952 році.

Рішення

1:

data['gdpPercap_1982']

2:

data.loc['Denmark',:]

3:

data.loc[:,'gdpPercap_1985':]

Pandas достатньо розумний, щоб розпізнати число в кінці мітки стовпця та не видає вам помилку, хоча стовпця з назвою gdpPercap_1985 насправді не існує. Це корисно, якщо нові стовпці додаються до файлу CSV пізніше.

4:

data['gdpPercap_2007']/data['gdpPercap_1952']

Використання функції dir для перегляду доступних методів

Python включає функцію dir, яку можна використовувати для відображення всіх доступних методів (функцій), вбудованих в об’єкт даних. Як приклад, функції, доступні для list data type:

potatoes = ["Russet", "Norkota", "Yukon Gold", "Pontiac"]
dir(potatoes)

Ця команда повертає:

['__add__',
...
'__subclasshook__',
 'append',
 'clear',
 'copy',
 'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']

Функції подвійного підкреслення можна поки що ігнорувати; функції, які не оточені подвійним підкресленням, є загальнодоступним інтерфейсом list type. Отже, якщо ви хочете відсортувати список картоплі відповідно до dir, вам слід спробувати

potatoes.sort()

Припустимо, Pandas було імпортовано, а дані Gapminder про ВВП для Європи завантажено як data. Потім скористайтеся dir, щоб знайти функцію, яка друкує середній ВВП на душу населення для всіх європейських країн за кожен рік, коли інформація доступна.

Рішення

Серед багатьох варіантів dir пропонує функцію median() як можливість. Таким чином,

data.median()

Інтерпретація

Кордони Польщі стабільні з 1945 року, але кілька разів змінювалися перед цим. Як би ви впоралися з цим, якби створювали таблицю ВВП на душу населення для Польщі на все ХХ століття?

Ключові моменти

  • Використовуйте DataFrame.iloc[..., ...] для вибору значень за їх позицією.

  • Використовуйте : окремо для позначення всіх стовпців або всіх рядків.

  • Вибирайте кілька стовпців або рядків за допомогою DataFrame.loc і визначеного зрізу.

  • Результат зрізу можна використовувати в подальших операціях.

  • Використовуйте порівняння для вибору даних на основі певного значення.

  • Виберіть значення або NaN за допомогою булевої маски.