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[..., ...]
для вибору значень за їх позицією
- Можна вказати позицію значення за допомогою числового індексу аналогічно 2D-версії вибору символів у рядках.
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[..., ...]
, щоб вибрати значення за їх міткою.
- Можна вказати позицію за допомогою імені рядка аналогічно до 2D-версії ключів словника.
data = pd.read_csv('data/gapminder_gdp_europe.csv', index_col='country')
print(data.loc["Albania", "gdpPercap_1952"])
1601.056136
Використовуйте :
окремо для позначення всіх стовпців або всіх рядків.
- Так само, як у звичайній Python нотації зрізу.
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
- Той самий результат можна отримати, якщо надрукувати
data.loc["Albania"]
(без другого індексу).
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
- Той самий результат можна отримати, якщо надрукувати
data["gdpPercap_1952"]
- Також можна отримати той самий результат, застосовуючи нотацію
data.gdpPercap_1952
(не рекомендовано, оскільки її легко сплутати з позначенням.
для методів).
Вибирайте кілька стовпців або рядків за допомогою 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
Використовуйте порівняння для вибору даних на основі певного значення.
- Порівняння здійснюється поелементно.
- Повертає фрейм даних подібної форми, що містить
True
іFalse
.
# Використовуйте підмножину даних, щоб результат був читабельним.
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 ~~~
- Отримайте значення, якщо маска є істинною, і NaN (не число), якщо вона хибна.
- Корисно, оскільки NaN ігноруються такими операціями, як max, min, average тощо.
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 — це функції, які надають користувачам велику гнучкість для аналізу своїх даних.
Наприклад, скажімо, ми хочемо мати більш чітке уявлення про те, як європейські країни розподілені відповідно до свого ВВП.
- Ми можемо поглянути, розділивши країни на дві групи протягом досліджуваних років, на тих, у кого ВВП вищий за середній європейський, та тих, у кого ВВП нижчий.
- Потім ми оцінюємо показник заможності на основі історичних значень (з 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
Ступінь зріза
- Чи дають два наведені нижче твердження однаковий результат?
- Виходячи з цього, яке правило керує тим, що включено (чи ні) до числових і іменованих зрізів у 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 про ВВП для Європи завантажено. Напишіть вираз, щоб вибрати кожне з наступного:
- ВВП на душу населення для всіх країн у 1982р.
- ВВП на душу населення для Данії за всі роки.
- ВВП на душу населення для всіх країн за роки після 1985.
- ВВП на душу населення для кожної країни у 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 за допомогою булевої маски.