una seleccionar hacer filas fila eliminar data crear columnas columna añadir agregar python pandas dataframe

hacer - seleccionar filas data frame python



Cómo explotar una lista dentro de una celda de Dataframe en filas separadas (10)

Estoy buscando convertir una celda de pandas que contiene una lista en filas para cada uno de esos valores.

Entonces, toma esto:

Si quisiera desempaquetar y apilar los valores en la columna de nearest_neighbors para que cada valor sea una fila dentro de cada índice de opponent , ¿cuál sería la mejor manera de hacerlo? ¿Existen métodos de pandas para operaciones como esta?


Aquí hay una optimización potencial para marcos de datos más grandes. Esto se ejecuta más rápido cuando hay varios valores iguales en el campo "explosivo". (Cuanto mayor sea el marco de datos en comparación con el recuento de valores únicos en el campo, mejor funcionará este código).

def lateral_explode(dataframe, fieldname): temp_fieldname = fieldname + ''_made_tuple_'' dataframe[temp_fieldname] = dataframe[fieldname].apply(tuple) list_of_dataframes = [] for values in dataframe[temp_fieldname].unique().tolist(): list_of_dataframes.append(pd.DataFrame({ temp_fieldname: [values] * len(values), fieldname: list(values), })) dataframe = dataframe[list(set(dataframe.columns) - set([fieldname]))]/ .merge(pd.concat(list_of_dataframes), how=''left'', on=temp_fieldname) del dataframe[temp_fieldname] return dataframe


Creo que esta es una muy buena pregunta, en Hive EXPLODE , creo que hay que argumentar que Pandas debería incluir esta funcionalidad por defecto. Probablemente explotaría la columna de la lista con una comprensión de generador anidada como esta:

pd.DataFrame({ "name": i[0], "opponent": i[1], "nearest_neighbor": neighbour } for i, row in df.iterrows() for neighbour in row.nearest_neighbors ).set_index(["name", "opponent"])


El método más rápido que encontré hasta ahora es extender el DataFrame con .iloc y asignar de nuevo la columna de destino aplanada .

Dada la entrada habitual (replicada un poco):

df = (pd.DataFrame({''name'': [''A.J. Price''] * 3, ''opponent'': [''76ers'', ''blazers'', ''bobcats''], ''nearest_neighbors'': [[''Zach LaVine'', ''Jeremy Lin'', ''Nate Robinson'', ''Isaia'']] * 3}) .set_index([''name'', ''opponent''])) df = pd.concat([df]*10) df Out[3]: nearest_neighbors name opponent A.J. Price 76ers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] blazers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] bobcats [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] 76ers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] blazers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] ...

Dadas las siguientes alternativas sugeridas:

col_target = ''nearest_neighbors'' def extend_iloc(): # Flatten columns of lists col_flat = [item for sublist in df[col_target] for item in sublist] # Row numbers to repeat lens = df[col_target].apply(len) vals = range(df.shape[0]) ilocations = np.repeat(vals, lens) # Replicate rows and add flattened column of lists cols = [i for i,c in enumerate(df.columns) if c != col_target] new_df = df.iloc[ilocations, cols].copy() new_df[col_target] = col_flat return new_df def melt(): return (pd.melt(df[col_target].apply(pd.Series).reset_index(), id_vars=[''name'', ''opponent''], value_name=col_target) .set_index([''name'', ''opponent'']) .drop(''variable'', axis=1) .dropna() .sort_index()) def stack_unstack(): return (df[col_target].apply(pd.Series) .stack() .reset_index(level=2, drop=True) .to_frame(col_target))

Encuentro que extend_iloc() es el más rápido :

%timeit extend_iloc() 3.11 ms ± 544 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) %timeit melt() 22.5 ms ± 1.25 ms per loop (mean ± std. dev. of 7 runs, 100 loops each) %timeit stack_unstack() 11.5 ms ± 410 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)


En el siguiente código, primero restablezco el índice para facilitar la iteración de la fila.

Creo una lista de listas donde cada elemento de la lista externa es una fila del DataFrame de destino y cada elemento de la lista interna es una de las columnas. Esta lista anidada finalmente se concatenará para crear el DataFrame deseado.

Utilizo una función lambda junto con la iteración de la lista para crear una fila para cada elemento de los nearest_neighbors emparejados con el name y el opponent relevantes.

Finalmente, creo un nuevo DataFrame a partir de esta lista (usando los nombres de columna originales y configurando el índice de nuevo a name y opponent ).

df = (pd.DataFrame({''name'': [''A.J. Price''] * 3, ''opponent'': [''76ers'', ''blazers'', ''bobcats''], ''nearest_neighbors'': [[''Zach LaVine'', ''Jeremy Lin'', ''Nate Robinson'', ''Isaia'']] * 3}) .set_index([''name'', ''opponent''])) >>> df nearest_neighbors name opponent A.J. Price 76ers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] blazers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] bobcats [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] df.reset_index(inplace=True) rows = [] _ = df.apply(lambda row: [rows.append([row[''name''], row[''opponent''], nn]) for nn in row.nearest_neighbors], axis=1) df_new = pd.DataFrame(rows, columns=df.columns).set_index([''name'', ''opponent'']) >>> df_new nearest_neighbors name opponent A.J. Price 76ers Zach LaVine 76ers Jeremy Lin 76ers Nate Robinson 76ers Isaia blazers Zach LaVine blazers Jeremy Lin blazers Nate Robinson blazers Isaia bobcats Zach LaVine bobcats Jeremy Lin bobcats Nate Robinson bobcats Isaia

EDITAR JUNIO 2017

Un método alternativo es el siguiente:

>>> (pd.melt(df.nearest_neighbors.apply(pd.Series).reset_index(), id_vars=[''name'', ''opponent''], value_name=''nearest_neighbors'') .set_index([''name'', ''opponent'']) .drop(''variable'', axis=1) .dropna() .sort_index() )


Entonces, todas estas respuestas son buenas, pero quería algo ^ realmente simple ^, así que aquí está mi contribución:

df = (pd.DataFrame({''name'': [''A.J. Price''] * 3, ''opponent'': [''76ers'', ''blazers'', ''bobcats''], ''nearest_neighbors'': [[''Zach LaVine'', ''Jeremy Lin'', ''Nate Robinson'', ''Isaia'']] * 3}) .set_index([''name'', ''opponent''])) df.explode(''nearest_neighbors'')

Eso es todo ... solo usa esto cuando quieras una nueva serie donde las listas están ''explotadas''. Aquí hay un ejemplo donde hacemos value_counts () en opciones de tacos :)

nearest_neighbors name opponent A.J. Price 76ers Zach LaVine 76ers Jeremy Lin 76ers Nate Robinson 76ers Isaia blazers Zach LaVine blazers Jeremy Lin blazers Nate Robinson blazers Isaia bobcats Zach LaVine bobcats Jeremy Lin bobcats Nate Robinson bobcats Isaia


Explotar una columna tipo lista se ha simplificado significativamente en pandas 0.25 con la adición del método explode() :

def explode(series): return pd.Series([x for _list in series for x in _list])

Fuera:

In [1]: my_df = pd.DataFrame(pd.Series([[''a'',''b'',''c''],[''b'',''c''],[''c'']]), columns=[''tacos'']) In [2]: my_df.head() Out[2]: tacos 0 [a, b, c] 1 [b, c] 2 [c] In [3]: explode(my_df[''tacos'']).value_counts() Out[3]: c 3 b 2 a 1


Extender la respuesta .iloc de Oleg para aplanar automáticamente todas las columnas de la lista:

def extend_iloc(df): cols_to_flatten = [colname for colname in df.columns if isinstance(df.iloc[0][colname], list)] # Row numbers to repeat lens = df[cols_to_flatten[0]].apply(len) vals = range(df.shape[0]) ilocations = np.repeat(vals, lens) # Replicate rows and add flattened column of lists with_idxs = [(i, c) for (i, c) in enumerate(df.columns) if c not in cols_to_flatten] col_idxs = list(zip(*with_idxs)[0]) new_df = df.iloc[ilocations, col_idxs].copy() # Flatten columns of lists for col_target in cols_to_flatten: col_flat = [item for sublist in df[col_target] for item in sublist] new_df[col_target] = col_flat return new_df

Esto supone que cada columna de lista tiene la misma longitud de lista.


Similar a la funcionalidad EXPLODE de Hive:

import copy def pandas_explode(df, column_to_explode): """ Similar to Hive''s EXPLODE function, take a column with iterable elements, and flatten the iterable to one element per observation in the output table :param df: A dataframe to explod :type df: pandas.DataFrame :param column_to_explode: :type column_to_explode: str :return: An exploded data frame :rtype: pandas.DataFrame """ # Create a list of new observations new_observations = list() # Iterate through existing observations for row in df.to_dict(orient=''records''): # Take out the exploding iterable explode_values = row[column_to_explode] del row[column_to_explode] # Create a new observation for every entry in the exploding iterable & add all of the other columns for explode_value in explode_values: # Deep copy existing observation new_observation = copy.deepcopy(row) # Add one (newly flattened) value from exploding iterable new_observation[column_to_explode] = explode_value # Add to the list of new observations new_observations.append(new_observation) # Create a DataFrame return_df = pandas.DataFrame(new_observations) # Return return return_df


Solución alternativa más agradable con apply (pd.Series):

df = pd.DataFrame({''listcol'':[[1,2,3],[4,5,6]]}) # expand df.listcol into its own dataframe tags = df[''listcol''].apply(pd.Series) # rename each variable is listcol tags = tags.rename(columns = lambda x : ''listcol_'' + str(x)) # join the tags dataframe back to the original dataframe df = pd.concat([df[:], tags[:]], axis=1)


Use apply(pd.Series) y stack , luego reset_index y to_frame

In [1803]: (df.nearest_neighbors.apply(pd.Series) .stack() .reset_index(level=2, drop=True) .to_frame(''nearest_neighbors'')) Out[1803]: nearest_neighbors name opponent A.J. Price 76ers Zach LaVine 76ers Jeremy Lin 76ers Nate Robinson 76ers Isaia blazers Zach LaVine blazers Jeremy Lin blazers Nate Robinson blazers Isaia bobcats Zach LaVine bobcats Jeremy Lin bobcats Nate Robinson bobcats Isaia

Detalles

In [1804]: df Out[1804]: nearest_neighbors name opponent A.J. Price 76ers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] blazers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia] bobcats [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]