Подтвердить что ты не робот

Pandas Список хранимых данных DataFrame как строка: как преобразовать обратно в список?

У меня есть n-by-m Pandas DataFrame df, определяемый следующим образом. (Я знаю, что это не лучший способ сделать это. Это имеет смысл для того, что я пытаюсь сделать в своем фактическом коде, но это будет TMI для этого сообщения, поэтому просто смените мое слово, что этот подход работает в моем конкретном сценарии.)

>>> df = DataFrame(columns=['col1'])
>>> df.append(Series([None]), ignore_index=True)
>>> df
Empty DataFrame
Columns: [col1]
Index: []

Я сохранил списки в ячейках этого DataFrame следующим образом.

>>> df['column1'][0] = [1.23, 2.34]
>>> df
     col1
0  [1, 2]

По какой-то причине DataFrame сохранил этот список как строку, а не список.

>>> df['column1'][0]
'[1.23, 2.34]'

У меня есть 2 вопроса для вас.

  • Почему DataFrame хранит список в виде строки и существует ли способ этого поведения?
  • Если нет, то есть ли Pythonic способ преобразования этой строки в список?

Обновление

Используемый мной DataFrame был сохранен и загружен из формата CSV. Этот формат, а не сам DataFrame, преобразовал список из строки в литерал.

4b9b3361

Ответ 1

Как вы указали, это может произойти при сохранении и загрузке pandas DataFrames в виде файлов .csv, который является текстовым форматом.

В вашем случае это произошло потому, что объекты списка имеют строковое представление, позволяющее хранить их как .csv файлы. Загрузка .csv приведет к тому, что это строковое представление.

Если вы хотите сохранить фактические объекты, вы должны использовать DataFrame.to_pickle() (обратите внимание: объекты должны быть сорваны!).

Чтобы ответить на второй вопрос, вы можете преобразовать его с помощью ast.literal_eval:

>>> from ast import literal_eval
>>> literal_eval('[1.23, 2.34]')
[1.23, 2.34]

Ответ 2

Я столкнулся с этой проблемой, и есть очень простое решение (pandas.eval()). Я использую 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'])

Ответ 3

1) Есть способ обойти это поведение. Используйте loc помогает здесь.

>>> 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) Pythonic способ конвертировать эту строку в список. (Это, вероятно, то, что вам нужно, поскольку используемый вами DataFrame был сохранен и загружен из формата CSV, для этого есть несколько решений). Это дополнение к ответу 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]

Ответ 4

только для справки... pandas не конвертировать списки в строку...

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'

Ответ 5

У меня была та же проблема. При хранении столбца списка данных в CSV файле с использованием df.to_csv() столбцы списка преобразуются в строку, например. "[42, 42, 42]" вместо [42, 42, 42]

Ответ Alex правильный, и вы можете использовать literal_eval для преобразования строки в список. Проблема с этим подходом заключается в том, что вам нужно импортировать дополнительную библиотеку, и вам нужно применить или сопоставить функцию с вашим фреймворком данных. Более простым способом является заставить Pandas читать столбец как объект Python (dtype)

df["col1"].astype('O')

O используется для объектов Python, включая списки. Подробнее здесь. Обратите внимание, что этот метод терпит неудачу, если вы разбираете строки с пустым списком: "[]"

В качестве альтернативы вы также можете применить функцию к своему столбцу (это для целых чисел):

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))

Ответ 6

Вы можете напрямую использовать панд -
df = pd.read_csv(df_name, converters={'column_name': eval})

Это будет читать этот столбец как соответствующий ему dtype в python вместо строки.

Ответ 7

Простой взлом, который я использовал, - это вызов лямбда-функции, которая индексирует первый и последний элементы (скобки списка в форме str) и вызывает метод split, за которым следует другой, который заменяет элементы списка на int.

df['column1'] = df['column1'].apply(lambda x:x[1:-1].split(',')).apply(lambda x:[int(i) for i in x])