Учебный ноутбук по теме "Пакет Pandas"

автор: Александр Дьяконов (alexanderdyakonov.wordpress.com)

In [2]:
# подгружаем все нужные пакеты
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
In [ ]:
# загрузка данных

# 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') # сохранение
In [50]:
# создание дата-фрейма

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
In [60]:
# простейшие операции
# столбцы
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
In [61]:
# индексация
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
Out[61]:
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
In [63]:
# операции с НаНами
# маска Нанов
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
Out[63]:
A B
0 1 2.2
1 NaN NaN
2 2 NaN
3 1 0.0
In [64]:
# как часто встречаются пары значений
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'])
Out[64]:
B 1 2 3 4
A
1 1 0 1 1
2 1 1 2 0
3 0 1 0 1
In [65]:
# все строки, в которых столбец начинается с определённой буквы
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'))]
Out[65]:
A B
0 1 as
4 2 aaa
5 3 a
In [66]:
# замена определённых значений
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
Out[66]:
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
In [67]:
# использование масок
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
Out[67]:
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
In [71]:
# объединение дата-фреймов
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
Out[71]:
key l r
0 1 1 4
1 1 3 4
2 2 2 5
In [85]:
# добавление к дата-фрейму
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
Out[85]:
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
In [69]:
# информация
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)
In [72]:
# временные ряды
# создание
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
In [73]:
# решение задачи
# для каждого унакального значения 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
In [74]:
# операции по группам (индуцируются разбиением по определённому признаку)
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
Out[74]:
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
In [75]:
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
Out[75]:
A B
A
1 3 2
2 4 1
In [76]:
# Строковые операции
s = pd.Series(['AbA', 'Sasha', 'DataMining']) # ( [] )
s.str.lower()
Out[76]:
0           aba
1         sasha
2    datamining
dtype: object
In [77]:
# иерархическая (многоуровневая) индексация
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
In [41]:
# панель (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
Out[41]:
<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
In [78]:
# графика
d = pd.DataFrame({"IQ": [1,4,3,2]})
d.index = ['man', 'woman', 'dog', 'cat']
d.plot(kind='barh')
Out[78]:
<matplotlib.axes.AxesSubplot at 0xb28fcf8>
In [79]:
# создание категориального признака = интервалы попаданий
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
Out[79]:
(-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
In [ ]:
#???
# категорный тип (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