Учебный ноутбук по теме "Пакет Pandas"
автор: Александр Дьяконов (alexanderdyakonov.wordpress.com)
# подгружаем все нужные пакеты
import pandas as pd
import numpy as np
# для встроенных картинок
%pylab inline
# чуть покрасивше картинки:
pd.set_option('display.mpl_style', 'default')
figsize(10, 3)
Populating the interactive namespace from numpy and matplotlib
# загрузка данных
# Excel
data2 = pd.read_excel('D:\\filename.xlsx', sheetname='1')
# csv-файл
data = pd.read_csv('D:\\filename.csv', sep=';', decimal=',')
data.to_csv('foo.csv') # сохранение
# HDF5
pd.read_hdf('foo.h5', 'df')
df.to_hdf('foo.h5', 'df') # сохранение
# создание дата-фрейма
data = pd.DataFrame({ 'A' : [1., 4., 2., 1.],
'B' : pd.Timestamp('20130102'),
'C' : pd.Series(1,index=list(range(4)),dtype='float32'),
'D' : np.array([3] * 4,dtype='int32'),
'E' : pd.Categorical(["test","train","test","train"]),
'F' : 'foo' }, index=pd.period_range('Jan-2000', periods=4, freq='M'))
print data
# второй способ
tmp = dict([('A',[1., np.nan, 2., 1.]), ('B',[2.2, np.nan, np.nan, 0.0])]) # ещё один способ
data2 = pd.DataFrame(tmp)
print data2
A B C D E F 2000-01 1 2013-01-02 NaN 3 test foo 2000-02 4 2013-01-02 NaN 3 train foo 2000-03 2 2013-01-02 NaN 3 test foo 2000-04 1 2013-01-02 NaN 3 train foo A B 0 1 2.2 1 NaN NaN 2 2 NaN 3 1 0.0
# простейшие операции
# столбцы
print data.columns
# строки - но тут временная индексация
print data.index
# сами данные
print data
# сортировка
print data.sort(columns='A')
# типы
print data.dtypes
# статистика + транспонирование
print data.describe().T
Index([u'A', u'B', u'C', u'D', u'E', u'F'], dtype='object') <class 'pandas.tseries.period.PeriodIndex'> [2000-01, ..., 2000-04] Length: 4, Freq: M A B C D E F 2000-01 1 2013-01-02 NaN 3 test foo 2000-02 4 2013-01-02 NaN 3 train foo 2000-03 2 2013-01-02 NaN 3 test foo 2000-04 1 2013-01-02 NaN 3 train foo A B C D E F 2000-01 1 2013-01-02 NaN 3 test foo 2000-04 1 2013-01-02 NaN 3 train foo 2000-03 2 2013-01-02 NaN 3 test foo 2000-02 4 2013-01-02 NaN 3 train foo A float64 B datetime64[ns] C float32 D int32 E object F object dtype: object count mean std min 25% 50% 75% max A 4 2 1.414214 1 1 1.5 2.5 4 C 0 NaN NaN NaN NaN NaN NaN NaN D 4 3 0.000000 3 3 3.0 3.0 3
# индексация
data.at['2000-01','A'] = 10.
print data.loc['2000-01':'2000-02',['D','B','A']]
data.iat[0,1] = pd.Timestamp('19990101') # просто = '1999/01/01' не работает
print data.iloc[0:2,1:3]
# выбор с проверкой на вхождение
print data[data['E'].isin(['test','valid'])]
# если не делать принт - выглядит круче
data.tail(3).T
D B A 2000-01 3 2013-01-02 10 2000-02 3 2013-01-02 4 B C 2000-01 1999-01-01 NaN 2000-02 2013-01-02 NaN A B C D E F 2000-01 10 1999-01-01 NaN 3 test foo 2000-03 2 2013-01-02 NaN 3 test foo
2000-02 | 2000-03 | 2000-04 | |
---|---|---|---|
A | 4 | 2 | 1 |
B | 2013-01-02 00:00:00 | 2013-01-02 00:00:00 | 2013-01-02 00:00:00 |
C | NaN | NaN | NaN |
D | 3 | 3 | 3 |
E | train | test | train |
F | foo | foo | foo |
# операции с НаНами
# маска Нанов
print data2.isnull()
# nan автоматически не учитываются
print data2.mean()
# тоже обходятся nan:
print data2.apply(np.cumsum)
# удаление Нанов
data3 = data2.dropna()
print data3
# заполнение Нанов
print data2.fillna(value=5.5)
# заполнение соседними значениями
print data2.ffill()
# не забывать data2 = data2.fillna(value=5.5)
data2
A B 0 False False 1 True True 2 False True 3 False False A 1.333333 B 1.100000 dtype: float64 A B 0 1 2.2 1 NaN NaN 2 3 NaN 3 4 2.2 A B 0 1 2.2 3 1 0.0 A B 0 1.0 2.2 1 5.5 5.5 2 2.0 5.5 3 1.0 0.0 A B 0 1 2.2 1 1 2.2 2 2 2.2 3 1 0.0
A | B | |
---|---|---|
0 | 1 | 2.2 |
1 | NaN | NaN |
2 | 2 | NaN |
3 | 1 | 0.0 |
# как часто встречаются пары значений
d = pd.DataFrame({'A': [1,2,2,1,2,3,2,1,3], 'B': [1,2,3,4,1,2,3,3,4]})
pd.crosstab(d['A'], d['B'])
B | 1 | 2 | 3 | 4 |
---|---|---|---|---|
A | ||||
1 | 1 | 0 | 1 | 1 |
2 | 1 | 1 | 2 | 0 |
3 | 0 | 1 | 0 | 1 |
# все строки, в которых столбец начинается с определённой буквы
d = pd.DataFrame({'A': [1,2,2,1,2,3,2,1,3], 'B': ['as','bs','e','qq','aaa','a','e','qwr','www']})
d[d['B'].map(lambda x: x.startswith('a'))]
A | B | |
---|---|---|
0 | 1 | as |
4 | 2 | aaa |
5 | 3 | a |
# замена определённых значений
d = pd.DataFrame({'A': [1,2,2,1,2,3,2,1,3], 'B': [1,2,3,4,1,2,3,3,4]})
d['B'][d['A']==1] = 0
# второй способ: d.ix[d['A']==1, 'B'] = 0
d
A | B | |
---|---|---|
0 | 1 | 0 |
1 | 2 | 2 |
2 | 2 | 3 |
3 | 1 | 0 |
4 | 2 | 1 |
5 | 3 | 2 |
6 | 2 | 3 |
7 | 1 | 0 |
8 | 3 | 4 |
# использование масок
d = pd.DataFrame({'A': [1,2,2,1,2,3,2,1,3], 'B': [1,2,3,4,1,2,3,3,4]})
mask = d>1
print mask.T
d = d.where(mask,2)
d['C'] = np.where(d['B']>3, 'high', 'low')
d.T
0 1 2 3 4 5 6 7 8 A False True True False True True True False True B False True True True False True True True True
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
---|---|---|---|---|---|---|---|---|---|
A | 2 | 2 | 2 | 2 | 2 | 3 | 2 | 2 | 3 |
B | 2 | 2 | 3 | 4 | 2 | 2 | 3 | 3 | 4 |
C | low | low | low | high | low | low | low | low | high |
# объединение дата-фреймов
left = pd.DataFrame({'key': [1,2,1], 'l': [1, 2, 3]})
right = pd.DataFrame({'key': [1,2,3], 'r': [4, 5, 6]})
print left
print right
pd.merge(left, right, on='key')
key l 0 1 1 1 2 2 2 1 3 key r 0 1 4 1 2 5 2 3 6
key | l | r | |
---|---|---|---|
0 | 1 | 1 | 4 |
1 | 1 | 3 | 4 |
2 | 2 | 2 | 5 |
# добавление к дата-фрейму
tmp = dict([('A',[1., 3., 2., 1.]), ('B',[2.2, 1.1, 3.3, 0.0]), ('C', 1)]) # ещё один способ
df = pd.DataFrame(tmp)
# добавление к дата-фрейму
df = df.append(df.iloc[1:3])
df
A | B | C | |
---|---|---|---|
0 | 1 | 2.2 | 1 |
1 | 3 | 1.1 | 1 |
2 | 2 | 3.3 | 1 |
3 | 1 | 0.0 | 1 |
1 | 3 | 1.1 | 1 |
2 | 2 | 3.3 | 1 |
# информация
data.info() # по памяти
#??? data.memory_usage() # аналогично
<class 'pandas.core.frame.DataFrame'> PeriodIndex: 4 entries, 2000-01 to 2000-04 Data columns (total 6 columns): A 4 non-null float64 B 4 non-null datetime64[ns] C 0 non-null float32 D 4 non-null int32 E 4 non-null object F 4 non-null object dtypes: datetime64[ns](1), float32(1), float64(1), int32(1), object(2)
# временные ряды
# создание
rng = pd.date_range('1/1/2012', periods=9, freq='D')
# дни
print rng.day
# дни недели
print rng.weekday
rng = pd.date_range('1/1/2012', periods=200, freq='S')
ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
# ресэмплирование
ts = ts.resample('Min', how='sum')
print ts
# ???
ts.tz_localize('UTC')
print ts
[1 2 3 4 5 6 7 8 9] [6 0 1 2 3 4 5 6 0] 2012-01-01 00:00:00 15255 2012-01-01 00:01:00 13164 2012-01-01 00:02:00 14217 2012-01-01 00:03:00 5326 Freq: T, dtype: int32 2012-01-01 00:00:00 15255 2012-01-01 00:01:00 13164 2012-01-01 00:02:00 14217 2012-01-01 00:03:00 5326 Freq: T, dtype: int32
# решение задачи
# для каждого унакального значения A найти минимальный B
import pandas as pd
d = pd.DataFrame({'A': [1,2,2,1,3,3], 'B': [1,2,3,3,2,1]})
print d
# первый способ
print d.loc[d.groupby('A')['B'].idxmin()]
# второй способ
print d.sort('B').groupby('A', as_index=False).first()
A B 0 1 1 1 2 2 2 2 3 3 1 3 4 3 2 5 3 1 A B 0 1 1 1 2 2 5 3 1 A B 0 1 1 1 2 2 2 3 1
# операции по группам (индуцируются разбиением по определённому признаку)
d = pd.DataFrame({'A': [1,2,2,1,1,2,2], 'B': [1,2,np.nan,5,3,1,10]})
d = d.sort('A')
print d
d['shift_B'] = d.groupby('A')['B'].shift(1) # сдвиг групп
d['counts'] = d.groupby(['A'])['B'].transform(len) # число элементов в группе
d
A B 0 1 1 3 1 5 4 1 3 1 2 2 2 2 NaN 5 2 1 6 2 10
A | B | shift_B | counts | |
---|---|---|---|---|
0 | 1 | 1 | NaN | 3 |
3 | 1 | 5 | 1 | 3 |
4 | 1 | 3 | 5 | 3 |
1 | 2 | 2 | NaN | 4 |
2 | 2 | NaN | 2 | 4 |
5 | 2 | 1 | NaN | 4 |
6 | 2 | 10 | 1 | 4 |
d = pd.DataFrame({'A': [1,2,2,1,1,2,2], 'B': [1,0,np.nan,1,0,1,0]})
d = d.sort('A')
print d
# длина и сколько 1 в каждой группе
d.groupby('A').agg({'A': len, 'B': lambda x: sum(x == 1)})
A B 0 1 1 3 1 1 4 1 0 1 2 0 2 2 NaN 5 2 1 6 2 0
A | B | |
---|---|---|
A | ||
1 | 3 | 2 |
2 | 4 | 1 |
# Строковые операции
s = pd.Series(['AbA', 'Sasha', 'DataMining']) # ( [] )
s.str.lower()
0 aba 1 sasha 2 datamining dtype: object
# иерархическая (многоуровневая) индексация
tuples = list(zip(*[['bar', 'bar', 'baz', 'baz',
'foo', 'foo', 'qux', 'qux'],
['one', 'two', 'one', 'two',
'one', 'two', 'one', 'two']]))
print tuples
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
print index
index
df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B'])
print df
print df.stack() # обратная операция unstack()
[('bar', 'one'), ('bar', 'two'), ('baz', 'one'), ('baz', 'two'), ('foo', 'one'), ('foo', 'two'), ('qux', 'one'), ('qux', 'two')] first second bar one two baz one two foo one two qux one two A B first second bar one -0.240469 -0.533312 two -0.847305 0.845316 baz one 0.274592 0.473476 two 1.433575 -0.977992 foo one 0.957252 -1.246396 two -2.821039 -0.625924 qux one 0.086683 -0.450850 two -1.236494 0.706156 first second bar one A -0.240469 B -0.533312 two A -0.847305 B 0.845316 baz one A 0.274592 B 0.473476 two A 1.433575 B -0.977992 foo one A 0.957252 B -1.246396 two A -2.821039 B -0.625924 qux one A 0.086683 B -0.450850 two A -1.236494 B 0.706156 dtype: float64
# панель (3D-дата-фрейм)
d = pd.DataFrame({'A': [1,2,2], 'B': [1,2,3]})
d2, d3 = d.copy(), d.copy()
p = pd.Panel({'df1':d, 'df2':d2, 'df3':d3})
p = p.transpose(2,0,1)
print p['A']
p
0 1 2 df1 1 2 2 df2 1 2 2 df3 1 2 2
<class 'pandas.core.panel.Panel'> Dimensions: 2 (items) x 3 (major_axis) x 3 (minor_axis) Items axis: A to B Major_axis axis: df1 to df3 Minor_axis axis: 0 to 2
# графика
d = pd.DataFrame({"IQ": [1,4,3,2]})
d.index = ['man', 'woman', 'dog', 'cat']
d.plot(kind='barh')
<matplotlib.axes.AxesSubplot at 0xb28fcf8>
# создание категориального признака = интервалы попаданий
x = np.random.randn(10000)
y = pd.cut(x,10)
z = pd.value_counts(y)
z.plot(figsize=(20,3))
pd.DataFrame(x).plot(kind='kde')
pd.DataFrame(z).T
(-0.211, 0.629] | (-1.0502, -0.211] | (0.629, 1.468] | (-1.89, -1.0502] | (1.468, 2.308] | (-2.729, -1.89] | (2.308, 3.147] | (-3.569, -2.729] | (3.147, 3.987] | (-4.417, -3.569] | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 3247 | 2638 | 1921 | 1192 | 634 | 226 | 102 | 32 | 6 | 2 |
#???
# категорный тип (new)
tmp = dict([('A',[1, 1, 2, 2]), ('B',[1., 2., 1., 2.])]) # ещё один способ
df = pd.DataFrame(tmp)
df['A'] = df['A'].astype('category') # преобразование в категорный тип
print df['A'].cat.categories
df