python - values - replace string with nan pandas
Pandas DataFrame almacena la lista como una cadena: ¿Cómo convertir de nuevo a la lista? (5)
Tengo un n- by- m Pandas DataFrame df
definido de la siguiente manera. (Sé que esta no es la mejor manera de hacerlo. Tiene sentido lo que estoy tratando de hacer en mi código real, pero sería TMI para esta publicación así que tome mi palabra de que este enfoque funciona en mi situación particular .)
>>> df = DataFrame(columns=[''col1''])
>>> df.append(Series([None]), ignore_index=True)
>>> df
Empty DataFrame
Columns: [col1]
Index: []
Almacenaba listas en las celdas de este DataFrame de la siguiente manera.
>>> df[''column1''][0] = [1.23, 2.34]
>>> df
col1
0 [1, 2]
Por algún motivo, DataFrame almacenó esta lista como una cadena en lugar de una lista.
>>> df[''column1''][0]
''[1.23, 2.34]''
Tengo 2 preguntas para ti.
- ¿Por qué DataFrame almacena una lista como una cadena y hay alguna forma de evitar este comportamiento?
- Si no, ¿hay una forma Pythonic para convertir esta cadena en una lista?
Actualizar
El DataFrame que estaba usando se ha guardado y cargado desde un formato CSV. Este formato, en lugar del propio DataFrame, convirtió la lista de una cadena a un literal.
1) Hay una forma de evitar este comportamiento. Usar loc ayuda aquí.
>>> import pandas as pd
>>> df = pd.DataFrame(columns=[''column1''])
>>> df = df.append(pd.Series(data = {''column1'':[None]}), ignore_index = True)
column1
0 [None]
>>> # Add list to index 0 in column1
>>> df.loc[0,''column1''] = [1.23, 2.34]
>>> print(df.loc[0, ''column1''])
[1.23, 2.34]
2) forma pitónica para convertir esta cadena en una lista. (Esto es probablemente lo que desea, ya que el DataFrame que está utilizando se ha guardado y cargado desde un formato CSV; hay un par de soluciones para esto). Esta es una adición en la respuesta de pshep123.
from ast import literal_eval
import pandas as pd
csv = io.StringIO(u''''''
id list
A1 [1,2]
A2 [3,4]
A3 [5,6]
'''''')
df = pd.read_csv(csv, delim_whitespace = True)
# Output is a string
df.loc[0, ''list'']
''[1,2]''
# Convert entire column to a list
df.loc[:,''list''] = df.loc[:,''list''].apply(lambda x: literal_eval(x))
# Output is a list
df.loc[0, ''list'']
[1, 2]
Acabo de encontrarme con este problema y hay una solución muy simple ( pandas.eval() ). Estoy usando pandas 0.20.0.
# SETUP
import pandas as pd
import io
csv = io.StringIO(u''''''
id list
A1 [1,2]
A2 [3,4]
A3 [5,6]
'''''')
df = pd.read_csv(csv, delim_whitespace = True)
# TYPE CHECK <type ''str''>
print type(df.at[0, ''list''])
# MAIN CONVERSION
df[''list''] = pd.eval(df[''list''])
# TYPE CHECK <type ''list''>
print type(df.at[0, ''list''])
Como ha señalado, esto puede ocurrir al guardar y cargar pandas DataFrames como archivos .csv
, que es un formato de texto.
En su caso, esto sucedió porque los objetos de la lista tienen una representación de cadena, lo que les permite almacenarse como archivos .csv
. Cargar el .csv
producirá esa representación de cadena.
Si desea almacenar los objetos reales, debe usar DataFrame.to_pickle()
(nota: los objetos deben ser seleccionables).
Para responder a su segunda pregunta, puede convertirla nuevamente con ast.literal_eval
:
>>> from ast import literal_eval
>>> literal_eval(''[1.23, 2.34]'')
[1.23, 2.34]
Yo tuve el mismo problema. Al almacenar una columna de lista de marcos de datos en un archivo CSV utilizando df.to_csv (), las columnas de listas se convierten en cadenas, por ejemplo, "[42, 42, 42]" en lugar de [42, 42, 42]
La respuesta de Alex es correcta y puedes usar literal_eval
para convertir la cadena nuevamente en una lista. El problema con este enfoque es que debe importar una biblioteca adicional y debe aplicar o asignar la función a su marco de datos. Como forma más fácil es forzar a Pandas a leer la columna como un objeto Python (dtype)
df["col1"].astype(''O'')
El O se usa para objetos de Python, incluidas las listas. Más información here . Tenga en cuenta que este método falla si analiza cadenas de listas vacías: "[]"
Alternativamente, también puede aplicar una función a su columna (esta es para enteros):
def stringToList(string):
# input format : "[42, 42, 42]" , note the spaces after the commas, in this case I have a list of integers
string = string[1:len(string)-1]
try:
if len(string) != 0:
tempList = string.split(", ")
newList = list(map(lambda x: int(x), tempList))
else:
newList = []
except:
newList = [-9999]
return(newList)
df["col1"] = df["col1"].apply(lambda x: stringToList(x))
solo como referencia ... los pandas no convierten listas en cadenas. ..
In [29]: data2 = [{''a'': [1, 5], ''b'': 2}, {''a'': 5, ''b'': 10, ''c'': 20}]
In [30]: df = pd.DataFrame(data2)
In [31]: df
Out[31]:
a b c
0 [1, 5] 2 NaN
1 5 10 20
In [32]: df[''a''][0], type(df[''a''][0])
Out[32]: ([1, 5], list)
In [33]: pd.__version__
Out[33]: ''0.12.0''