http://stackoverflow.com/questions/22670904/python-pandas-turn-absolute-periods-into-relative-periods/22671904?noredirect=1#comment34537319_22671904
this works, but I think could be more efficient on a whole frame basis
In [37]: def f(x):
....: y = x.dropna()
....: return Series(y.values,x.index[len(x)-len(y):])
....:
In [40]: roller = pd.rolling_sum(df,3).reset_index(drop=True)
In [41]: roller
Out[41]:
1 2 3
0 NaN NaN NaN
1 NaN NaN NaN
2 61 56 56
3 9 9 9
4 12 12 12
5 NaN 15 15
6 NaN NaN 11
7 NaN NaN NaN
[8 rows x 3 columns]
In [43]: roller.apply(f).reindex_like(roller)
Out[43]:
1 2 3
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN 56
4 NaN 56 9
5 61 9 12
6 9 12 15
7 12 15 11
[8 rows x 3 columns]
Comment From: dsm054
I think we'd want a call pattern which would support pulling the non-nan values up to the head -- which is actually what I usually need -- as well as pushing them down to the tail, so we'd need both an axis and a direction (a way to position "down").
Comment From: dsm054
I'm also not sure that dropna
is the right method to use, because this will never actually return a smaller frame. It's more like a shift + fillna.
Comment From: jreback
yep.....its more like movena
; not sure that really want another method name though.....
Comment From: dsm054
If we don't want to add a new method name, then maybe we should use fillna
. It already accepts a method argument, and we could simply add broll
/froll
or something (bfall
/ffall
)? Because fillna
can already return series/frames which still have nans, it's really like a "do something with some nans, maybe" in practice anyway.
Comment From: jreback
good idea! and I like those method names. you could use the limit
argument to put in spacers (e.g. offsets from the end) as well.
Comment From: jreback
maybe df.shift(method='broll')
or df.shift(3,method='froll')
Comment From: dsm054
Either would work for me: it's sort of a shift (because it repositions) and sort of a fillna (because it changes non-nan values based on the nan values -- or maybe I should say that the other way around.)
I'm not sure what df.shift(3, method='froll')
would do, though. Group all the non-nan values and assign them to .iloc[3:]
? To .iloc[:-3]
?
Comment From: jreback
how about head/tail instead of froll/broll then it's clear which end u r talking about
so df.shift(3,method='head') would give u 3 rows of nan followed by squashed data
this might be tricky as what if u can't fit the data in (after squashing) will it expand the frame?
Comment From: dsm054
If we're viewing falling as a special shift
, I don't think it should expand the frame because shift
wouldn't. But I wonder if we should make it explicit that it's different from a normal shift in that it's value-dependent, not merely index-dependent, and call it valid_to_head
or valid_to_tail
or notnull_to_head
or notnull_to_tail
.
[Aside: I don't care much about the behaviour of the df.shift(3, method='somename')
case because when I need this, I only ever need the non-nan values pushed to one of the edges.]
Comment From: jreback
what about df.shift('head|tail')
then? makes it clear what its doing
Comment From: dsm054
Syntactic question: so you mean to bypass the method
kwarg entirely and have us branch on periods
instead?
Semantic question: just to make sure we're breaking the symmetry the same way :^), do you mean that head
would push all the valid data to the start, and tail
to the end? (That's how I read it.)
Comment From: jreback
well, could branch on periods
or use a method kw (and make periods
optional),
maybe this is the best, and just raise if periods is None and method is None
Series.shift(periods=None,freq=None,method=None)
It think your meaning of head/tail is right (at least that's what I would expect)
Comment From: jbrockmendel
I think shift now takes a list. You’d need to figure out what to pass it so it would be a 2 liner instead of a single call.