Как преобразовать список в фреймворк pandas

У меня есть следующий код:

rows =[]
for dt in new_info:
    x =  dt['state']
    est = dt['estimates']

    col_R = [val['choice'] for val in est if val['party'] == 'Rep']
    col_D = [val['choice'] for val in est if val['party'] == 'Dem']

    incumb = [val['party'] for val in est if val['incumbent'] == True ]

    rows.append((x, col_R, col_D, incumb))

Теперь я хочу преобразовать список строк в фреймворк pandas. Строка списка моих строк показана ниже, а в моем списке 32 записи.

enter image description here

Когда я преобразовываю это в кадр данных pandas, я получаю записи в кадре данных как список.

pd.DataFrame(rows, columns=["State", "R", "D", "incumbent"])  

enter image description here

Но я хочу, чтобы мой кадр данных выглядел как

enter image description here

Новая информационная переменная выглядит так: enter image description here

Ответ 1

Поскольку вы не возражаете против объектов в списках столбцов, я бы использовал генератор для удаления списков, которые обертывают ваши элементы:

import pandas as pd
import numpy as np
rows = [(u'KY', [u'McConnell'], [u'Grimes'], [u'Rep']),
        (u'AR', [u'Cotton'], [u'Pryor'], [u'Dem']),
        (u'MI', [u'Land'], [u'Peters'], [])]

def get(r, nth):
    '''helper function to retrieve item from nth list in row r'''
    return r[nth][0] if r[nth] else np.nan

def remove_list_items(list_of_records):
    for r in list_of_records:
        yield r[0], get(r, 1), get(r, 2), get(r, 3)

Генератор работает аналогично этой функции, но вместо того, чтобы материализовать список без необходимости в памяти в качестве промежуточного шага, он просто передает каждую строку, которая будет в списке, пользователю списка строк:

def remove_list_items(list_of_records):
    result = []
    for r in list_of_records:
        result.append((r[0], get(r, 1), get(r, 2), get(r, 3)))
    return result

И затем составьте свой DataFrame, передавая ваши данные через генератор (или версию списка, если хотите).

>>> df = pd.DataFrame.from_records(
        remove_list_items(rows), 
        columns=["State", "R", "D", "incumbent"])
>>> df
  State          R       D incumbent
0    KY  McConnell  Grimes       Rep
1    AR     Cotton   Pryor       Dem
2    MI       Land  Peters       NaN

Или вы можете использовать понимание списка или выражение генератора (показано), чтобы сделать по существу то же самое:

>>> df = pd.DataFrame.from_records(
      ((r[0], get(r, 1), get(r, 2), get(r, 3)) for r in rows), 
      columns=["State", "R", "D", "incumbent"])

Ответ 2

Вы можете использовать некоторые встроенные манипуляции с списком python и сделать что-то вроде:

df['col1'] = df['col1'].apply(lambda i: ''.join(i))

который будет производить:

    col1 col2
0    a  [d]
1    b  [e]
2    c  [f]

Очевидно, что col2 не был отформатирован, чтобы показать контраст.

Изменить

В соответствии с запросом OP, если вы хотите внедрить apply(lambda...) ко всем столбцам, вы можете явно указать каждый столбец с строкой, которая выглядит как выше, заменяя 'col1' каждым из имен столбцов, которые вы хотите изменить или вы можете просто перебрать столбцы следующим образом:

если у вас есть фрейм данных типа

x = [['a'],['b'],['c'],['d']]
y = [['e'],['f'],['g'],['h']]
z = [['i'],['j'],['k'],['l']]

df = pd.DataFrame({'col1':x, 'col2':y, 'col3':z})

то вы можете перебрать столбцы

for col in df.columns:
    df[col] = df[col].apply(lambda i: ''.join(i))

который преобразует кадр данных, который начинается следующим образом:

   col1 col2 col3
0  [a]  [e]  [i]
1  [b]  [f]  [j]
2  [c]  [g]  [k]
3  [d]  [h]  [l]

и становится

    col1 col2 col3
0    a    e    i
1    b    f    j
2    c    g    k
3    d    h    l