I want to relace values in a dataframe, with a 0 where is a NaN value and with 1 where is a value.
here is my data:
AA AAPL FB GOOG TSLA XOM
Date
2018-02-28 NaN 0.068185 NaN NaN -0.031752 NaN
2018-03-31 -0.000222 NaN NaN NaN NaN -0.014920
2018-04-30 0.138790 NaN NaN NaN 0.104347 NaN
2018-05-31 NaN 0.135124 0.115 NaN NaN NaN
2018-06-30 NaN NaN NaN 0.028258 0.204474 NaN
2018-07-31 NaN 0.027983 NaN 0.091077 NaN NaN
2018-08-31 0.032355 0.200422 NaN NaN NaN NaN
2018-09-30 NaN -0.008303 NaN NaN NaN 0.060496
2018-10-31 NaN -0.030478 NaN NaN 0.274011 NaN
2018-11-30 NaN NaN NaN 0.016401 0.039013 NaN
2018-12-31 NaN NaN NaN -0.053745 -0.050445 NaN
Use mask and fillna:
df = df.mask(df.notna(), 1).fillna(0, downcast='infer')
Use:
df[df.notnull() == True] = 1
df.fillna(0, inplace=True)
Cast the Boolean values to int.
df.notnull().astype(int)
AA AAPL FB GOOG TSLA XOM
2018-02-28 0 1 0 0 1 0
2018-03-31 1 0 0 0 0 1
2018-04-30 1 0 0 0 1 0
2018-05-31 0 1 1 0 0 0
2018-06-30 0 0 0 1 1 0
Related
I have the following code where i try to copy the EXPIRATION from the recent dataframe to the EXPIRATION column in the destination dataframe:
recent = pd.read_excel(r'Y:\Attachments' + '\\' + '962021.xlsx')
print('HERE\n',recent)
print('HERE2\n', recent['EXPIRATION'])
destination= pd.read_excel(r'Y:\Attachments' + '\\' + 'Book1.xlsx')
print('HERE3\n', destination)
destination['EXPIRATION']= recent['EXPIRATION']
print('HERE4\n', destination)
The problem is that destination has less rows than recent so some of the lower rows in the EXPIRATION column from recent do not end up in the destination dataframe. I want all the EXPIRATION values from recent to be in the destination dataframe, even if all the other values are NaN.
Example Output:
HERE
Unnamed: 0 IGNORE DATE_TRADE DIRECTION EXPIRATION NAME OPTION_TYPE PRICE QUANTITY STRATEGY STRIKE TIME_TRADE TYPE UNDERLYING
0 0 21 6/9/2021 B 08/06/2021 BNP FP E C 12 12 CONDORI 12 9:23:40 ETF NASDAQ
1 1 22 6/9/2021 B 16/06/2021 BNP FP E P 12 12 GOLD/SILVER 12 10:9:19 ETF NASDAQ
2 2 23 6/9/2021 B 16/06/2021 TEST P 12 12 CONDORI 21 10:32:12 EQT TEST
3 3 24 6/9/2021 B 22/06/2021 TEST P 12 12 GOLD/SILVER 12 10:35:5 EQT NASDAQ
4 4 0 6/9/2021 B 26/06/2021 TEST P 12 12 GOLD/SILVER 12 10:37:11 ETF FTSE100
HERE2
0 08/06/2021
1 16/06/2021
2 16/06/2021
3 22/06/2021
4 26/06/2021
Name: EXPIRATION, dtype: object
HERE3
Unnamed: 0 IGNORE DATE_TRADE DIRECTION EXPIRATION NAME OPTION_TYPE PRICE QUANTITY STRATEGY STRIKE TIME_TRADE TYPE UNDERLYING
0 NaN NaN NaN NaN 2 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN 1 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN 3 NaN NaN NaN NaN NaN NaN NaN NaN NaN
HERE4
Unnamed: 0 IGNORE DATE_TRADE DIRECTION EXPIRATION NAME OPTION_TYPE PRICE QUANTITY STRATEGY STRIKE TIME_TRADE TYPE UNDERLYING
0 NaN NaN NaN NaN 08/06/2021 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN 16/06/2021 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN 16/06/2021 NaN NaN NaN NaN NaN NaN NaN NaN NaN
Joining is generally the best approach, but I see that you have no id column apart from native pandas indexing, and there are only Nans in destination, so if you are sure that ordering is not a problem you can just use:
>>> destination = pd.concat([recent,destination[['EXPIRATION']]], ignore_index=True, axis=1)
Unnamed: 0 IGNORE DATE_TRADE DIRECTION EXPIRATION ...
0 NaN NaN NaN NaN 08/06/2021 ...
1 NaN NaN NaN NaN 16/06/2021 ...
2 NaN NaN NaN NaN 16/06/2021 ...
3 NaN NaN NaN NaN 22/06/2021 ...
4 NaN NaN NaN NaN 26/06/2021 ...
I have a datetime indexed series like this:
2018-08-27 17:45:01 1
2018-08-27 16:01:12 1
2018-08-27 13:48:47 1
2018-08-26 22:26:40 2
2018-08-26 20:10:42 1
2018-08-26 18:20:32 1
2018-08-25 23:07:51 1
2018-08-25 01:46:08 1
2018-09-18 14:08:23 1
2018-09-17 19:38:38 1
2018-09-15 22:40:45 1
What is an elegant way to reformat this into a time indexed dataframe whose columns are dates? For example:
2018-10-24 2018-06-28 2018-10-23
15:16:41 1.0 NaN NaN
15:18:16 1.0 NaN NaN
15:21:42 1.0 NaN NaN
23:35:00 NaN NaN 1.0
23:53:13 NaN 1.0 NaN
Current approach:
time_date_dict = defaultdict(partial(defaultdict, int))
for i in series.iteritems():
datetime = i[0]
value = i[1]
time_date_dict[datetime.time()][datetime.date()] = value
time_date_df = pd.DataFrame.from_dict(time_date_dict, orient='index')
Use pivot:
df1 = pd.pivot(s.index.time, s.index.date, s)
#if want strings index and columns names
#df1 = pd.pivot(s.index.strftime('%H:%M:%S'), s.index.strftime('%Y-%m-%d'), s)
print (df1)
date 2018-08-25 2018-08-26 2018-08-27 2018-09-15 2018-09-17 \
date
01:46:08 1.0 NaN NaN NaN NaN
13:48:47 NaN NaN 1.0 NaN NaN
14:08:23 NaN NaN NaN NaN NaN
16:01:12 NaN NaN 1.0 NaN NaN
17:45:01 NaN NaN 1.0 NaN NaN
18:20:32 NaN 1.0 NaN NaN NaN
19:38:38 NaN NaN NaN NaN 1.0
20:10:42 NaN 1.0 NaN NaN NaN
22:26:40 NaN 2.0 NaN NaN NaN
22:40:45 NaN NaN NaN 1.0 NaN
23:07:51 1.0 NaN NaN NaN NaN
date 2018-09-18
date
01:46:08 NaN
13:48:47 NaN
14:08:23 1.0
16:01:12 NaN
17:45:01 NaN
18:20:32 NaN
19:38:38 NaN
20:10:42 NaN
22:26:40 NaN
22:40:45 NaN
23:07:51 NaN
I have a pandas dataframe Date containing a column indicating a subject ID and several dates for each subject.
SubID date1 date2 .... daten
0 ID1 NaT NaN
1 ID2 2015-04-28 NaN
2 ID3 NaT NaN
The dates (date1, date2,....daten) contain NaT, NaN and dates in the form of yyyy-mm-dd.
I would like to count for each SubID how many "date" columns contain a real date.
in this small example I should have
SubID number of dates
0 ID1 0
1 ID2 1
2 ID3 0
I think you can use count with selecting columns by loc:
df['number of dates'] = df.loc[:,'date1':].count(axis=1)
Sample:
print (df)
SubID date1 date2
0 ID1 2015-04-28 2015-04-28
1 ID2 2015-04-28 NaT
2 ID3 NaT NaT
print (df.loc[:,'date1':])
date1 date2
0 2015-04-28 2015-04-28
1 2015-04-28 NaT
2 NaT NaT
df['number of dates'] = df.loc[:,'date1':].count(axis=1)
print (df)
SubID date1 date2 number of dates
0 ID1 2015-04-28 2015-04-28 2
1 ID2 2015-04-28 NaT 1
2 ID3 NaT NaT 0
Another solution with set_index and reset_index:
df = df.set_index('SubID')
df['number of dates'] = df.count(axis=1)
df = df.reset_index()
print (df)
SubID date1 date2 number of dates
0 ID1 2015-04-28 2015-04-28 2
1 ID2 2015-04-28 NaT 1
2 ID3 NaT NaT 0
df = pd.read_pickle('df')
df['number of dates'] = df.loc[:,'date1':].count(axis=1)
print (df)
SubID val_1_kalender_val1_a1 val_2_kalender_val1_a1_1 \
0 h2h_ht_ehv_p001_2 NaT NaN
1 h2h_ht_ehv_p002_3 2015-04-28 NaN
2 h2h_ht_ehv_p003_1 NaT NaN
3 h2h_ht_ehv_p004_4 NaT NaN
4 h2h_ht_ehv_p005_4 NaT NaN
5 h2h_ht_ehv_p006_1 NaT NaN
6 h2h_ht_ehv_p007_1 NaT NaN
7 h2h_ht_ehv_p008_3 2015-07-08 2015-08-06 00:00:00
8 h2h_ht_ehv_p009_3 2015-06-03 NaN
9 h2h_ht_ehv_p010_3 NaT NaN
10 h2h_ht_ehv_p011_3 NaT NaN
11 NaN NaT NaN
12 h2h_ht_ehv_p013_1 NaT NaN
13 h2h_ht_ehv_p014_3 NaT NaN
14 h2h_ht_ehv_p015_1 NaT NaN
15 h2h_ht_ehv_p016_1 NaT NaN
16 h2h_ht_ehv_p017_3 NaT NaN
17 h2h_ht_ehv_p018_1 2015-06-26 2015-08-10 00:00:00
18 h2h_ht_ehv_p019_1 2015-06-18 2015-07-16 00:00:00
19 h2h_ht_ehv_p020_3 NaT NaN
20 h2h_ht_ehv_p021_3 2015-08-09 NaN
21 h2h_ht_ehv_p022_3 2015-07-05 NaN
22 h2h_ht_ehv_p023_3 NaT NaN
23 h2h_ht_ehv_p024_3 NaT NaN
24 h2h_ht_ehv_p025_3 NaT NaN
25 h2h_ht_ehv_p026_3 2015-09-12 NaN
26 h2h_ht_ehv_p027_3 NaT NaN
27 h2h_ht_ehv_p028_3 NaT NaN
28 h2h_ht_ehv_p029_3 NaT NaN
29 h2h_ht_ehv_p030_3 NaT NaN
.. ... ... ...
99 h2h_ht_ehv_p100_3 NaT NaN
100 h2h_ht_ehv_p101_3 NaT NaN
101 h2h_ht_ehv_p102_3 NaT NaN
102 h2h_ht_ehv_p103_1 2016-06-14 NaN
103 h2h_ht_ehv_p104_3 NaT NaN
104 NaN 2016-02-12 NaN
105 h2h_ht_ehv_p106_3 NaT NaN
106 h2h_ht_ehv_p107_3 NaT NaN
107 h2h_ht_ehv_p108_3 NaT NaN
108 h2h_ht_ehv_p109_3 NaT NaN
109 h2h_ht_ehv_p110_1 NaT NaN
110 h2h_ht_ehv_p111_1 NaT NaN
111 h2h_ht_ehv_p112_3 NaT NaN
112 h2h_ht_ehv_p113_3 NaT NaN
113 h2h_ht_ehv_p114_3 2016-06-06 NaN
114 h2h_ht_ehv_p115_1 NaT NaN
115 h2h_ht_ehv_p116_3 2016-03-18 NaN
116 h2h_ht_ehv_p117_3 NaT NaN
117 h2h_ht_ehv_p118_3 NaT NaN
118 NaN NaT NaN
119 h2h_ht_ehv_p120_3 NaT NaN
120 h2h_ht_ehv_p121_3 NaT NaN
121 h2h_ht_ehv_p122_3 NaT NaN
122 h2h_ht_ehv_p123_3 2016-06-21 NaN
123 h2h_ht_ehv_p124_3 NaT NaN
124 h2h_ht_ehv_p125_3 2016-03-29 NaN
125 h2h_ht_ehv_p126_3 NaT NaN
126 h2h_ht_ehv_p127_1 NaT NaN
127 h2h_ht_ehv_p128_3 NaT NaN
128 h2h_ht_ehv_p129_3 NaT NaN
val_3_kalender_val1_a1_2 val_4_kalender_val1_a1_3 \
0 NaN NaN
1 NaN NaN
2 NaN NaN
3 NaN NaN
4 NaN NaN
5 NaN NaN
6 NaN NaN
7 NaN NaN
8 NaN NaN
9 NaN NaN
10 NaN NaN
11 NaN NaN
12 NaN NaN
13 NaN NaN
14 NaN NaN
15 NaN NaN
16 NaN NaN
17 NaN NaN
18 2015-07-17 00:00:00 2015-07-27 00:00:00
19 NaN NaN
20 NaN NaN
21 NaN NaN
22 NaN NaN
23 NaN NaN
24 NaN NaN
25 NaN NaN
26 NaN NaN
27 NaN NaN
28 NaN NaN
29 NaN NaN
.. ... ...
99 NaN NaN
100 NaN NaN
101 NaN NaN
102 NaN NaN
103 NaN NaN
104 NaN NaN
105 NaN NaN
106 NaN NaN
107 NaN NaN
108 NaN NaN
109 NaN NaN
110 NaN NaN
111 NaN NaN
112 NaN NaN
113 NaN NaN
114 NaN NaN
115 NaN NaN
116 NaN NaN
117 NaN NaN
118 NaN NaN
119 NaN NaN
120 NaN NaN
121 NaN NaN
122 NaN NaN
123 NaN NaN
124 NaN NaN
125 NaN NaN
126 NaN NaN
127 NaN NaN
128 NaN NaN
val_5_kalender_val1_a1_4 val_6_kalender_val1_a1_5 \
0 NaN NaN
1 NaN NaN
2 NaN NaN
3 NaN NaN
4 NaN NaN
5 NaN NaN
6 NaN NaN
7 NaN NaN
8 NaN NaN
9 NaN NaN
10 NaN NaN
11 NaN NaN
12 NaN NaN
13 NaN NaN
14 NaN NaN
15 NaN NaN
16 NaN NaN
17 NaN NaN
18 2015-09-06 00:00:00 2015-10-03 00:00:00
19 NaN NaN
20 NaN NaN
21 NaN NaN
22 NaN NaN
23 NaN NaN
24 NaN NaN
25 NaN NaN
26 NaN NaN
27 NaN NaN
28 NaN NaN
29 NaN NaN
.. ... ...
99 NaN NaN
100 NaN NaN
101 NaN NaN
102 NaN NaN
103 NaN NaN
104 NaN NaN
105 NaN NaN
106 NaN NaN
107 NaN NaN
108 NaN NaN
109 NaN NaN
110 NaN NaN
111 NaN NaN
112 NaN NaN
113 NaN NaN
114 NaN NaN
115 NaN NaN
116 NaN NaN
117 NaN NaN
118 NaN NaN
119 NaN NaN
120 NaN NaN
121 NaN NaN
122 NaN NaN
123 NaN NaN
124 NaN NaN
125 NaN NaN
126 NaN NaN
127 NaN NaN
128 NaN NaN
val_7_kalender_val1_a1_6 val_8_kalender_val1_a1_7 \
0 NaN NaN
1 NaN NaN
2 NaN NaN
3 NaN NaN
4 NaN NaN
5 NaN NaN
6 NaN NaN
7 NaN NaN
8 NaN NaN
9 NaN NaN
10 NaN NaN
11 NaN NaN
12 NaN NaN
13 NaN NaN
14 NaN NaN
15 NaN NaN
16 NaN NaN
17 NaN NaN
18 NaN NaN
19 NaN NaN
20 NaN NaN
21 NaN NaN
22 NaN NaN
23 NaN NaN
24 NaN NaN
25 NaN NaN
26 NaN NaN
27 NaN NaN
28 NaN NaN
29 NaN NaN
.. ... ...
99 NaN NaN
100 NaN NaN
101 NaN NaN
102 NaN NaN
103 NaN NaN
104 NaN NaN
105 NaN NaN
106 NaN NaN
107 NaN NaN
108 NaN NaN
109 NaN NaN
110 NaN NaN
111 NaN NaN
112 NaN NaN
113 NaN NaN
114 NaN NaN
115 NaN NaN
116 NaN NaN
117 NaN NaN
118 NaN NaN
119 NaN NaN
120 NaN NaN
121 NaN NaN
122 NaN NaN
123 NaN NaN
124 NaN NaN
125 NaN NaN
126 NaN NaN
127 NaN NaN
128 NaN NaN
val_9_kalender_val1_a1_8 number of dates
0 NaN 0
1 NaN 1
2 NaN 0
3 NaN 0
4 NaN 0
5 NaN 0
6 NaN 0
7 NaN 2
8 NaN 1
9 NaN 0
10 NaN 0
11 NaN 0
12 NaN 0
13 NaN 0
14 NaN 0
15 NaN 0
16 NaN 0
17 NaN 2
18 NaN 6
19 NaN 0
20 NaN 1
21 NaN 1
22 NaN 0
23 NaN 0
24 NaN 0
25 NaN 1
26 NaN 0
27 NaN 0
28 NaN 0
29 NaN 0
.. ... ...
99 NaN 0
100 NaN 0
101 NaN 0
102 NaN 1
103 NaN 0
104 NaN 1
105 NaN 0
106 NaN 0
107 NaN 0
108 NaN 0
109 NaN 0
110 NaN 0
111 NaN 0
112 NaN 0
113 NaN 1
114 NaN 0
115 NaN 1
116 NaN 0
117 NaN 0
118 NaN 0
119 NaN 0
120 NaN 0
121 NaN 0
122 NaN 1
123 NaN 0
124 NaN 1
125 NaN 0
126 NaN 0
127 NaN 0
128 NaN 0
[129 rows x 11 columns]
I set up a new data frame SimMean:
columns = ['Tenor','5x16', '7x8', '2x16H']
index = range(0,12)
SimMean = pd.DataFrame(index=index, columns=columns)
SimMean
Tenor 5x16 7x8 2x16H
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 NaN NaN NaN NaN
3 NaN NaN NaN NaN
4 NaN NaN NaN NaN
5 NaN NaN NaN NaN
6 NaN NaN NaN NaN
7 NaN NaN NaN NaN
8 NaN NaN NaN NaN
9 NaN NaN NaN NaN
10 NaN NaN NaN NaN
11 NaN NaN NaN NaN
I have another data frame FwdDf:
FwdDf
Tenor 5x16 7x8 2x16H
0 2017-01-01 50.94 34.36 43.64
1 2017-02-01 50.90 32.60 42.68
2 2017-03-01 42.66 26.26 37.26
3 2017-04-01 37.08 22.65 32.46
4 2017-05-01 42.21 20.94 33.28
5 2017-06-01 39.30 22.05 32.29
6 2017-07-01 50.90 21.80 38.51
7 2017-08-01 42.77 23.64 35.07
8 2017-09-01 37.45 19.61 32.68
9 2017-10-01 37.55 21.75 32.10
10 2017-11-01 35.61 22.73 32.90
11 2017-12-01 40.16 29.79 37.49
12 2018-01-01 53.45 36.09 47.61
13 2018-02-01 52.89 35.74 45.00
14 2018-03-01 44.67 27.79 38.62
15 2018-04-01 38.48 24.21 34.43
16 2018-05-01 43.87 22.17 34.69
17 2018-06-01 40.24 22.85 34.31
18 2018-07-01 49.98 23.58 39.96
19 2018-08-01 45.57 24.76 37.23
20 2018-09-01 38.90 21.74 34.22
21 2018-10-01 39.75 23.36 35.20
22 2018-11-01 38.04 24.20 34.62
23 2018-12-01 42.68 31.03 40.00
now I need to assign the 'Tenor' data from row 12 to row 23 in FwdDf to the new data frame SimMean.
I used
SimMean.loc[0:11,'Tenor'] = FwdDf.loc [12:23,'Tenor']
but it didn't work:
SimMean
Tenor 5x16 7x8 2x16H
0 None NaN NaN NaN
1 None NaN NaN NaN
2 None NaN NaN NaN
3 None NaN NaN NaN
4 None NaN NaN NaN
5 None NaN NaN NaN
6 None NaN NaN NaN
7 None NaN NaN NaN
8 None NaN NaN NaN
9 None NaN NaN NaN
10 None NaN NaN NaN
11 None NaN NaN NaN
I'm new to python. I would appreciate your help. Thanks
call .values so there are no index alignment issues:
In [35]:
SimMean.loc[0:11,'Tenor'] = FwdDf.loc[12:23,'Tenor'].values
SimMean
Out[35]:
Tenor 5x16 7x8 2x16H
0 2018-01-01 NaN NaN NaN
1 2018-02-01 NaN NaN NaN
2 2018-03-01 NaN NaN NaN
3 2018-04-01 NaN NaN NaN
4 2018-05-01 NaN NaN NaN
5 2018-06-01 NaN NaN NaN
6 2018-07-01 NaN NaN NaN
7 2018-08-01 NaN NaN NaN
8 2018-09-01 NaN NaN NaN
9 2018-10-01 NaN NaN NaN
10 2018-11-01 NaN NaN NaN
11 2018-12-01 NaN NaN NaN
EDIT
As your column is actually datetime then you need to convert the type again:
In [46]:
SimMean['Tenor'] = pd.to_datetime(SimMean['Tenor'])
SimMean
Out[46]:
Tenor 5x16 7x8 2x16H
0 2018-01-01 NaN NaN NaN
1 2018-02-01 NaN NaN NaN
2 2018-03-01 NaN NaN NaN
3 2018-04-01 NaN NaN NaN
4 2018-05-01 NaN NaN NaN
5 2018-06-01 NaN NaN NaN
6 2018-07-01 NaN NaN NaN
7 2018-08-01 NaN NaN NaN
8 2018-09-01 NaN NaN NaN
9 2018-10-01 NaN NaN NaN
10 2018-11-01 NaN NaN NaN
11 2018-12-01 NaN NaN NaN
The issue below was created in Python 2.7.11 with Pandas 0.17.1
When grouping a categorical column with both a period and date column, unexpected rows appear in the grouping. Is this a Pandas bug, or could it be something else?
df = pd.DataFrame({'date': pd.date_range('2015-12-29', '2016-1-3'),
'val1': [1] * 6,
'val2': range(6),
'cat1': ['a', 'b', 'c'] * 2,
'cat2': ['A', 'B', 'C'] * 2})
df['cat1'] = df.cat1.astype('category')
df['month'] = [d.to_period('M') for d in df.date]
>>> df
cat1 cat2 date val1 val2 month
0 a A 2015-12-29 1 0 2015-12
1 b B 2015-12-30 1 1 2015-12
2 c C 2015-12-31 1 2 2015-12
3 a A 2016-01-01 1 3 2016-01
4 b B 2016-01-02 1 4 2016-01
5 c C 2016-01-03 1 5 2016-01
Grouping the month and date with a regular series (e.g. cat2) works as expected:
>>> df.groupby(['month', 'date', 'cat2']).sum().unstack()
val1 val2
cat2 A B C A B C
month date
2015-12 2015-12-29 1 NaN NaN 0 NaN NaN
2015-12-30 NaN 1 NaN NaN 1 NaN
2015-12-31 NaN NaN 1 NaN NaN 2
2016-01 2016-01-01 1 NaN NaN 3 NaN NaN
2016-01-02 NaN 1 NaN NaN 4 NaN
2016-01-03 NaN NaN 1 NaN NaN 5
But grouping on a categorical produces unexpected results. You'll notice in the index that the extra dates do not correspond to the grouped month.
>>> df.groupby(['month', 'date', 'cat1']).sum().unstack()
val1 val2
cat1 a b c a b c
month date
2015-12 2015-12-29 1 NaN NaN 0 NaN NaN
2015-12-30 NaN 1 NaN NaN 1 NaN
2015-12-31 NaN NaN 1 NaN NaN 2
2016-01-01 NaN NaN NaN NaN NaN NaN # <<< Extraneous row.
2016-01-02 NaN NaN NaN NaN NaN NaN # <<< Extraneous row.
2016-01-03 NaN NaN NaN NaN NaN NaN # <<< Extraneous row.
2016-01 2015-12-29 NaN NaN NaN NaN NaN NaN # <<< Extraneous row.
2015-12-30 NaN NaN NaN NaN NaN NaN # <<< Extraneous row.
2015-12-31 NaN NaN NaN NaN NaN NaN # <<< Extraneous row.
2016-01-01 1 NaN NaN 3 NaN NaN
2016-01-02 NaN 1 NaN NaN 4 NaN
2016-01-03 NaN NaN 1 NaN NaN 5
Grouping the categorical by month periods or dates works fine, but not when both are combined as in the example above.
>>> df.groupby(['month', 'cat1']).sum().unstack()
val1 val2
cat1 a b c a b c
month
2015-12 1 1 1 0 1 2
2016-01 1 1 1 3 4 5
>>> df.groupby(['date', 'cat1']).sum().unstack()
val1 val2
cat1 a b c a b c
date
2015-12-29 1 NaN NaN 0 NaN NaN
2015-12-30 NaN 1 NaN NaN 1 NaN
2015-12-31 NaN NaN 1 NaN NaN 2
2016-01-01 1 NaN NaN 3 NaN NaN
2016-01-02 NaN 1 NaN NaN 4 NaN
2016-01-03 NaN NaN 1 NaN NaN 5
EDIT
This behavior originated in the 0.15.0 update. Prior to that, this was the output:
>>> df.groupby(['month', 'date', 'cat1']).sum().unstack()
val1 val2
cat1 a b c a b c
month date
2015-12 2015-12-29 1 NaN NaN 0 NaN NaN
2015-12-30 NaN 1 NaN NaN 1 NaN
2015-12-31 NaN NaN 1 NaN NaN 2
2016-01 2016-01-01 1 NaN NaN 3 NaN NaN
2016-01-02 NaN 1 NaN NaN 4 NaN
2016-01-03 NaN NaN 1 NaN NaN 5
As defined in pandas, grouping with a categorical will always have the full set of categories, even if there isn't any data with that category, e.g., doc example here
You can either not use a categorical, or add a .dropna(how='all') after your grouping step.