exportar - pandas plot pie chart
Cómo crear una estructura de datos retrasada usando el marco de datos pandas (6)
Como se mencionó, podría valer la pena mirar las funciones rolling_ , lo que significará que no tendrá tantas copias alrededor.
Una solución es concat serie shifted para hacer un DataFrame:
In [11]: pd.concat([s, s.shift(), s.shift(2)], axis=1)
Out[11]:
0 1 2
1 5 NaN NaN
2 4 5 NaN
3 3 4 5
4 2 3 4
5 1 2 3
In [12]: pd.concat([s, s.shift(), s.shift(2)], axis=1).dropna()
Out[12]:
0 1 2
3 3 4 5
4 2 3 4
5 1 2 3
Trabajar en esto será más eficiente que en las listas ...
Ejemplo
s=pd.Series([5,4,3,2,1], index=[1,2,3,4,5])
print s
1 5
2 4
3 3
4 2
5 1
¿Hay una manera eficiente de crear una serie. por ejemplo, que contiene en cada fila los valores retrasados (en este ejemplo hasta el retraso 2)
3 [3, 4, 5]
4 [2, 3, 4]
5 [1, 2, 3]
Esto corresponde a s = pd.Serie ([[3,4,5], [2,3,4], [1,2,3]], índice = [3,4,5])
¿Cómo se puede hacer esto de manera eficiente para los marcos de datos con muchas series temporales que son muy largas?
Gracias
Editado después de ver las respuestas.
ok, al final implementé esta función:
def buildLaggedFeatures(s,lag=2,dropna=True):
''''''
Builds a new DataFrame to facilitate regressing over all possible lagged features
''''''
if type(s) is pd.DataFrame:
new_dict={}
for col_name in s:
new_dict[col_name]=s[col_name]
# create lagged Series
for l in range(1,lag+1):
new_dict[''%s_lag%d'' %(col_name,l)]=s[col_name].shift(l)
res=pd.DataFrame(new_dict,index=s.index)
elif type(s) is pd.Series:
the_range=range(lag+1)
res=pd.concat([s.shift(i) for i in the_range],axis=1)
res.columns=[''lag_%d'' %i for i in the_range]
else:
print ''Only works for DataFrame or Series''
return None
if dropna:
return res.dropna()
else:
return res
produce los resultados deseados y gestiona la denominación de las columnas en el DataFrame resultante.
Para una serie como entrada:
s=pd.Series([5,4,3,2,1], index=[1,2,3,4,5])
res=buildLaggedFeatures(s,lag=2,dropna=False)
lag_0 lag_1 lag_2
1 5 NaN NaN
2 4 5 NaN
3 3 4 5
4 2 3 4
5 1 2 3
y para un DataFrame como entrada:
s2=s=pd.DataFrame({''a'':[5,4,3,2,1], ''b'':[50,40,30,20,10]},index=[1,2,3,4,5])
res2=buildLaggedFeatures(s2,lag=2,dropna=True)
a a_lag1 a_lag2 b b_lag1 b_lag2
3 3 4 5 30 40 50
4 2 3 4 20 30 40
5 1 2 3 10 20 30
Me gusta poner los números de retraso en las columnas haciendo que las columnas sean un MultiIndex
. De esta manera, se conservan los nombres de las columnas.
Aquí hay un ejemplo del resultado:
# Setup
indx = pd.Index([1, 2, 3, 4, 5], name=''time'')
s=pd.Series(
[5, 4, 3, 2, 1],
index=indx,
name=''population'')
shift_timeseries_by_lags(pd.DataFrame(s), [0, 1, 2])
Resultado: un multiindex DataFrame con dos etiquetas de columna: el original ("población") y uno nuevo ("retraso"):
Solución : Al igual que en la solución aceptada, usamos DataFrame.shift
y luego pandas.concat
.
def shift_timeseries_by_lags(df, lags, lag_label=''lag''):
return pd.concat([
shift_timeseries_and_create_multiindex_column(df, lag,
lag_label=lag_label)
for lag in lags], axis=1)
def shift_timeseries_and_create_multiindex_column(
dataframe, lag, lag_label=''lag''):
return (dataframe.shift(lag)
.pipe(append_level_to_columns_of_dataframe,
lag, lag_label))
Me gustaría que hubiera una manera fácil de agregar una lista de etiquetas a las columnas existentes. Aquí está mi solución.
def append_level_to_columns_of_dataframe(
dataframe, new_level, name_of_new_level, inplace=False):
"""Given a (possibly MultiIndex) DataFrame, append labels to the column
labels and assign this new level a name.
Parameters
----------
dataframe : a pandas DataFrame with an Index or MultiIndex columns
new_level : scalar, or arraylike of length equal to the number of columns
in `dataframe`
The labels to put on the columns. If scalar, it is broadcast into a
list of length equal to the number of columns in `dataframe`.
name_of_new_level : str
The label to give the new level.
inplace : bool, optional, default: False
Whether to modify `dataframe` in place or to return a copy
that is modified.
Returns
-------
dataframe_with_new_columns : pandas DataFrame with MultiIndex columns
The original `dataframe` with new columns that have the given `level`
appended to each column label.
"""
old_columns = dataframe.columns
if not hasattr(new_level, ''__len__'') or isinstance(new_level, str):
new_level = [new_level] * dataframe.shape[1]
if isinstance(dataframe.columns, pd.MultiIndex):
new_columns = pd.MultiIndex.from_arrays(
old_columns.levels + [new_level],
names=(old_columns.names + [name_of_new_level]))
elif isinstance(dataframe.columns, pd.Index):
new_columns = pd.MultiIndex.from_arrays(
[old_columns] + [new_level],
names=([old_columns.name] + [name_of_new_level]))
if inplace:
dataframe.columns = new_columns
return dataframe
else:
copy_dataframe = dataframe.copy()
copy_dataframe.columns = new_columns
return copy_dataframe
Actualización : aprendí de esta solución otra forma de poner un nuevo nivel en una columna, lo que hace que no sea necesario usar append_level_to_columns_of_dataframe
:
def shift_timeseries_by_lags_v2(df, lags, lag_label=''lag''):
return pd.concat({
''{lag_label}_{lag_number}''.format(lag_label=lag_label, lag_number=lag):
df.shift(lag)
for lag in lags},
axis=1)
Aquí está el resultado de shift_timeseries_by_lags_v2(pd.DataFrame(s), [0, 1, 2])
:
Para un df de marco de datos con el retraso que se aplicará en ''nombre de columna'', puede usar la función de cambio.
df[''lag1'']=df[''col name''].shift(1)
df[''lag2'']=df[''col name''].shift(2)
Para varios retrasos (muchos de ellos), esto podría ser más compacto:
df=pd.DataFrame({''year'': range(2000, 2010), ''gdp'': [234, 253, 256, 267, 272, 273, 271, 275, 280, 282]})
df.join(pd.DataFrame({''gdp_'' + str(lag): df[''gdp''].shift(lag) for lag in range(1,4)}))
Puedes hacer lo siguiente:
s=pd.Series([5,4,3,2,1], index=[1,2,3,4,5])
res = pd.DataFrame(index = s.index)
for l in range(3):
res[l] = s.shift(l)
print res.ix[3:,:].as_matrix()
Produce:
array([[ 3., 4., 5.],
[ 2., 3., 4.],
[ 1., 2., 3.]])
que espero que sea muy cercano a lo que realmente quieres.
Solución muy simple usando pandas DataFrame:
number_lags = 3
df = pd.DataFrame(data={''vals'':[5,4,3,2,1]})
for lag in xrange(1, number_lags + 1):
df[''lag_'' + str(lag)] = df.vals.shift(lag)
#if you want numpy arrays with no null values:
df.dropna().values for numpy arrays