Python Pandas Pivot Table - python

I am trying to do a pivot table of frequency counts using Pandas.
I have the following code:
from pandas import pivot_table, DataFrame, crosstab
import numpy as np
df=DataFrame(
{'Y':[99999991, 99999992, 99999993, 99999994, 99999995,
99999996, 99999997, 99999998, 99999999],
'X':[1, 2, 3, 4, 5, 6, 7, 8, 9],
'X2':[1, 2, 3, 4, 5, 6, 7, 8, 9]})
print pivot_table(df,rows=['Y'], cols=['X'],aggfunc=np.sum)
This is my output:
X 1 2 3 4 5 6 7 8 9
Y
99999991 1 NaN NaN NaN NaN NaN NaN NaN NaN
99999992 NaN 2 NaN NaN NaN NaN NaN NaN NaN
99999993 NaN NaN 3 NaN NaN NaN NaN NaN NaN
99999994 NaN NaN NaN 4 NaN NaN NaN NaN NaN
99999995 NaN NaN NaN NaN 5 NaN NaN NaN NaN
99999996 NaN NaN NaN NaN NaN 6 NaN NaN NaN
99999997 NaN NaN NaN NaN NaN NaN 7 NaN NaN
99999998 NaN NaN NaN NaN NaN NaN NaN 8 NaN
99999999 NaN NaN NaN NaN NaN NaN NaN NaN 9
This is my desired output:
X 1 2 3 4 5 6 7 8 9
X2
1 99999991 NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN 99999992 NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN 99999993 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN 99999994 NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN 99999995 NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN 99999996 NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN 99999997 NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN 99999998 NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN 99999999
This is what I keep getting:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 9 entries, 1 to 9
Data columns:
('Y', 1L) 1 non-null values
('Y', 2L) 1 non-null values
('Y', 3L) 1 non-null values
('Y', 4L) 1 non-null values
('Y', 5L) 1 non-null values
('Y', 6L) 1 non-null values
('Y', 7L) 1 non-null values
('Y', 8L) 1 non-null values
('Y', 9L) 1 non-null values
dtypes: float64(9)
Does anyone know why? Is the output too big. I can't seem to find anything on it.

Just replace rows=['Y'] with rows=['X2']
>>> print pivot_table(df,rows=['X2'], cols=['X'],aggfunc=np.sum)
Y
X 1 2 3 4 5 6 7 8 9
X2
1 101 NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN 102 NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN 103 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN 104 NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN 105 NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN 106 NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN 107 NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN 108 NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN 109

Try this:
In [3]: df.pivot_table('Y', rows='X', cols='X2')
X2 1 2 3 4 5 6 7 8 9
X
1 99999991 NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN 99999992 NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN 99999993 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN 99999994 NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN 99999995 NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN 99999996 NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN 99999997 NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN 99999998 NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN 99999999
This would also work:
pivot_table(df, 'Y', rows='X', cols='X2')
or
pivot_table(df, rows='X', cols='X2')['Y']

Related

Changing the Values of a Multi-Index Dataframe

I have a multi-index dataframe that is set up as follows:
index = pd.MultiIndex.from_product([['A','B','C'], ['x','y', 'z']])
multi_index = pd.DataFrame(np.nan, index=np.arange(10), columns=index)
Which produces the following output:
A B C
x y z x y z x y z
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN NaN
I am trying to fill the values of the multi-index data frame with values. As a toy example, what I've tried to do is change the value of ['A','x',0] as follows:
multi_index['A']['x'].loc[0] = 65.2
However, I receive a 'SettingWithCopyWarning', which makes sense to me. I've also tried
multi_index['A'].iloc[[1],0] = 65.2
and received the same warning.
Is there a way one can change the values of a multi-index dataframe on a entry-by-entry basis? I.E changing the 0th index of ['A','x']?
Try:
multi_index.loc[0, ('A', 'x')] = 65.2
You can use tuples with loc for index labelling to access your multiindex columns or rows.
Or you can use iloc like this using integer index position selection, for example 2 here is the third column:
multi_index.iloc[0, 2] = 70.3
Output:
A B C
x y z x y z x y z
0 65.2 NaN 70.3 NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN NaN

Cubic interpolation in Pandas raises ValueError: The number of derivatives at boundaries does not match: expected 2, got 0+0

I am getting the following error
ValueError: The number of derivatives at boundaries does not match: expected 2, got 0+0
while trying to use cubic interpolation in pandas on a 2d matrix.
mat = pd.read_csv("m.csv")
mat = mat.interpolate(method='cubic')
Csv to reproduce can be downloaded here
I think the issue is that you need at least 4 points for cubic interpolation, look at this : question. It works for column 0:
mat['0'].interpolate(method='cubic', inplace=True)
print(mat)
0 1 2 3 4 5 6 7 8 9 10 11 12 13
0 -0.000347 NaN 0.002546 NaN 0.001891 NaN NaN NaN 0.001845 NaN 0.001507 NaN 0.000452 NaN
1 0.000210 NaN NaN NaN NaN NaN NaN 0.002109 NaN NaN NaN NaN NaN NaN
2 0.000438 NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.004112 NaN NaN NaN
3 0.000419 NaN NaN 0.001114 NaN 0.000599 0.003813 NaN 0.003342 NaN NaN NaN 0.001095 NaN
4 0.000240 0.001143 NaN 0.002955 NaN 0.004867 0.000857 NaN 0.002584 NaN NaN 0.002765 -0.000012 NaN
5 -0.000016 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 -0.000264 NaN NaN -0.000257 NaN 0.002049 0.001710 NaN -0.000041 NaN NaN NaN 0.000934 NaN
7 -0.000419 0.003044 NaN NaN NaN NaN NaN NaN NaN NaN 0.001225 NaN NaN NaN
8 -0.000397 NaN 0.001417 NaN NaN NaN NaN 0.001647 NaN NaN NaN NaN NaN NaN
9 -0.000169 NaN NaN NaN NaN 0.000154 NaN NaN NaN 0.000424 -0.000507 NaN 0.000550 NaN
10 0.000072 NaN NaN 0.000768 NaN NaN 0.000315 NaN NaN 0.000055 -0.000477 NaN 0.002413 NaN
11 0.000078 NaN NaN NaN NaN 0.000512 NaN NaN NaN NaN NaN NaN NaN NaN
12 -0.000399 NaN NaN NaN NaN 0.003461 0.001000 NaN NaN NaN NaN NaN 0.001112 NaN
13 -0.001608 NaN 0.001928 NaN NaN NaN NaN NaN NaN 0.001780 0.002132 NaN NaN NaN

Filtering from pandas pivot table by value in a row

I created a (large) sparse matrix by a pivot table.
UserId ...
1 5.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
5 NaN NaN NaN NaN NaN 2.0 NaN NaN NaN NaN ...
... ... ... ... ... ... ... ... ... ... ... ...
6036 NaN NaN NaN 2.0 NaN 3.0 NaN NaN NaN NaN ...
6037 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
6038 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
6039 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
6040 3.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN ...
MovieId 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952
UserId
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ...
6036 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6037 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6038 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6039 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6040 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
Now, I am looking for a way for, given a row index (e.g. 1) select all index whose values are > 4.0. Is there a simple way to do so?.
I tried the following
df.loc[1] >= 4.0
however what I get is
MovieId
1 True
2 False
3 False
4 False
5 False
...
3948 False
3949 False
3950 False
3951 False
3952 False
Name: 1, Length: 3706, dtype: bool
meaning I am almost there, but not quite. How do I extract the indices corresponding to True?
You can chain two loc selections, the first selects the rows based on label, the second will use a function to subset the columns based on your condition. Or you could use a single nested loc, where the columns mask also calls .loc
import numpy as np
import pandas as pd
np.random.seed(42)
df = pd.DataFrame(np.random.choice([1, np.NaN, 5], p=[.2, .7, .1], size=(2, 40)))
df.loc[1].loc[lambda x: x >= 4]
#or
df.loc[1, df.loc[1] >= 4]
#3 5.0
#10 5.0
#12 5.0
#15 5.0
#29 5.0
#Name: 1, dtype: float64

dropna() for multiple columns

Here is a sample of my dataframe:
benzene toluene styrene xylenes + ethylbenzene 1,3,5-trimethylbenzene propylbenzene chlorobenzene 4-ethyltoluene isopropyl benzene 1,3-butadiene
0 1.1040 NaN NaN NaN NaN NaN NaN NaN NaN 0.1914
1 1.1312 NaN NaN NaN NaN NaN NaN NaN NaN 0.2353
2 1.6092 NaN NaN NaN NaN NaN NaN NaN NaN 0.7289
3 1.2578 NaN NaN NaN NaN NaN NaN NaN NaN 0.3269
4 1.8245 NaN NaN NaN NaN NaN NaN NaN NaN 0.2859
5 1.1438 NaN NaN NaN NaN NaN NaN NaN NaN 0.1229
6 1.1492 NaN NaN NaN NaN NaN NaN NaN NaN 0.4135
7 0.8638 NaN NaN NaN NaN NaN NaN NaN NaN 0.6211
8 1.3209 NaN NaN NaN NaN NaN NaN NaN NaN 0.6243
9 1.8316 NaN NaN NaN NaN NaN NaN NaN NaN 0.6711
10 1.0491 NaN NaN NaN NaN NaN NaN NaN NaN 0.3379
11 1.5014 NaN NaN NaN NaN NaN NaN NaN NaN 0.7981
12 0.8355 NaN NaN NaN NaN NaN NaN NaN NaN 0.2950
13 1.5157 NaN NaN NaN NaN NaN NaN NaN NaN 0.7630
14 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
15 0.3561 NaN NaN NaN NaN NaN NaN NaN NaN 0.1983
16 16.9953 NaN NaN NaN NaN NaN NaN NaN NaN 11.6154
17 NaN 2.5533 1.7676 4.8479 2.1782 2.0693 NaN NaN NaN NaN
18 NaN 4.8740 4.5862 5.6155 5.3850 5.1158 NaN NaN NaN NaN
19 NaN 5.5761 7.1540 5.2305 7.0061 6.6558 NaN NaN NaN NaN
20 NaN 5.6369 8.0997 5.0377 7.4323 7.0607 NaN NaN NaN NaN
21 NaN 5.6762 8.5204 5.0503 7.9827 7.5835 NaN NaN NaN NaN
22 NaN 5.7317 8.9214 4.7230 8.4647 8.0415 NaN NaN NaN NaN
23 NaN 5.6349 8.3186 4.2832 8.4023 7.9822 NaN NaN NaN NaN
24 NaN 5.5504 9.1297 4.2451 8.2951 7.8803 NaN NaN NaN NaN
25 NaN 5.9629 9.0821 4.3384 9.0512 8.5986 NaN NaN NaN NaN
26 NaN 5.7665 10.1691 4.2266 8.9481 8.5007 NaN NaN NaN NaN
27 NaN 5.6709 9.1637 4.0334 9.0945 8.6397 NaN NaN NaN NaN
28 NaN 5.8178 8.8859 4.0104 9.0523 8.5997 NaN NaN NaN NaN
29 NaN 5.5470 9.0448 3.9718 8.8667 8.4233 NaN NaN NaN NaN
[...]
Actual size is 66x10
I have sequence of about 17 non NAN values for each column. I would like to drop the Nan cells to have a a full 17x10 table.
I used pd.DataFrame.dropna but it doesn't remove patches of cell. Is there a way to do so without looping over columns?
I think you can use apply with dropna:
df = df.apply(lambda x: pd.Series(x.dropna().values))
print (df)
Another numpy solution with sorting numpy array created by values and then remove rows with all NaN by dropna:
df = pd.DataFrame(np.sort(df.values, axis=0), index=df.index, columns=df.columns)
.dropna(how='all')
print (df)

Divide Dataframe by a series sharing index

I want to divide a DataFrame by one of its columns (a Series), they both share the index, so I expect the result has the shape of the original DataFrame.
This code shows what I did:
import numpy as np
import pandas as pd
cols = ['A', 'B', 'C', 'D']
ix = range(10)
df = pd.DataFrame(index=ix, columns=cols, data=np.random.randint(0, 100, size=(10, 4)))
print(df / df['A'])
The result is something like that:
0 1 2 3 4 5 6 7 8 9 A B C D
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
But I expect something like that:
A B C D
0 1 .. .. ..
1 1 .. .. ..
2 1 .. .. ..
3 1 .. .. ..
4 1 .. .. ..
5 1 .. .. ..
6 1 .. .. ..
7 1 .. .. ..
8 1 .. .. ..
9 89 94 14 44
Thanks in advance.
use div with axis=0, it's aligning on the columns hence you get the 0...9 and original columns, you should use div and explicitly pass axis=0 so it broadcasts along the index:
In [58]:
, axis=0
df.div(df['A'], axis=0)
Out[58]:
A B C D
0 1.0 0.818182 1.681818 0.431818
1 1.0 1.562500 0.625000 1.468750
2 1.0 17.000000 5.400000 2.800000
3 1.0 9.428571 13.857143 8.285714
4 1.0 0.256098 0.085366 1.146341
5 1.0 27.000000 21.500000 7.500000
6 1.0 0.444444 1.236111 1.041667
7 1.0 0.268293 0.048780 1.146341
8 1.0 0.505051 0.434343 0.101010
9 1.0 0.673684 0.378947 0.873684
You can see a related question: What does the term "broadcasting" mean in Pandas documentation? that illustrates the broadcasting rules

Categories

Resources