У меня есть dataframe, где некоторые ячейки содержат списки нескольких значений. Вместо того, чтобы хранить несколько значений в ячейке, я бы хотел расширить фрейм данных, чтобы каждый элемент в списке получил свою собственную строку (с такими же значениями во всех других столбцах). Так что если у меня есть:
import pandas as pd
import numpy as np
df = pd.DataFrame(
{'trial_num': [1, 2, 3, 1, 2, 3],
'subject': [1, 1, 1, 2, 2, 2],
'samples': [list(np.random.randn(3).round(2)) for i in range(6)]
}
)
df
Out[10]:
samples subject trial_num
0 [0.57, -0.83, 1.44] 1 1
1 [-0.01, 1.13, 0.36] 1 2
2 [1.18, -1.46, -0.94] 1 3
3 [-0.08, -4.22, -2.05] 2 1
4 [0.72, 0.79, 0.53] 2 2
5 [0.4, -0.32, -0.13] 2 3
Как мне преобразовать в длинную форму, например:
subject trial_num sample sample_num
0 1 1 0.57 0
1 1 1 -0.83 1
2 1 1 1.44 2
3 1 2 -0.01 0
4 1 2 1.13 1
5 1 2 0.36 2
6 1 3 1.18 0
# etc.
Индекс не важен, можно установить существующие столбцы в качестве индекса, а окончательный порядок не важен.
df.explode('samples')
чтобы решить эту проблему.explode
может поддерживать только взрыв одного столбца на данный момент.Ответы:
Результат:
PS здесь вы можете найти немного более общее решение
ОБНОВЛЕНИЕ: некоторые объяснения: IMO, самый простой способ понять этот код, это попытаться выполнить его шаг за шагом:
в следующей строке мы повторяем значения в одном столбце,
N
гдеN
- длина соответствующего списка:это может быть обобщено для всех столбцов, содержащих скалярные значения:
используя
np.concatenate()
мы можем сгладить все значения вlist
column (samples
) и получить одномерный вектор:положить все это вместе:
Использование
pd.DataFrame()[df.columns]
гарантирует, что мы выбираем столбцы в исходном порядке ...источник
lst_col
полностью; чтобы сохранить эти строки и заполнить ихlst_col
сnp.nan
, вы можете просто сделатьdf[lst_col] = df[lst_col].apply(lambda x: x if len(x) > 0 else [np.nan])
перед использованием этого метода. Очевидно ,.mask
не будет возвращать списки, следовательно.apply
.Чуть дольше, чем я ожидал:
Если вы хотите последовательный индекс, вы можете применить
reset_index(drop=True)
к результату.обновление :
источник
df.apply(lambda x: pd.Series(x['samples']),axis=1)
наdf.samples.apply(pd.Series)
.df.explode()
как показано здесь.Панды> = 0,25
Методы Series и DataFrame определяют
.explode()
метод, который разбивает списки на отдельные строки. См. Раздел «Документы» в разделе « Взрыв столбца в виде списка» .Обратите внимание, что это также обрабатывает смешанные столбцы списков и скаляров, а также соответственно пустые списки и NaN (это недостаток
repeat
решений на основе).Тем не менее, вы должны отметить, что
explode
работает только на одном столбце (на данный момент).PS: если вы хотите взорвать столбец строк , вам нужно сначала разделить разделитель, а затем использовать
explode
. Смотрите этот (очень) связанный ответ от меня.источник
Вы также можете использовать
pd.concat
иpd.melt
для этого:Наконец, если вам нужно, вы можете отсортировать базу по первым трем столбцам.
источник
Пытаясь пошагово поработать над решением Романа Пекара, чтобы лучше понять его, я придумал собственное решение, которое использует,
melt
чтобы избежать путаницы в стеке и сбросе индексов. Я не могу сказать, что это, очевидно, более ясное решение, хотя:Вывод (очевидно, теперь мы можем отбросить столбец исходных образцов):
источник
Для тех, кто ищет вариант ответа Романа Пекара, в котором не нужно именовать столбцы вручную:
источник
Я нашел самый простой способ:
samples
столбец в DataFrameПоказанный здесь:
Стоит отметить, что это могло сработать только потому, что в каждом испытании было одинаковое количество образцов (3). Что-то более умное может быть необходимо для испытаний с разными размерами выборки.
источник
Очень поздний ответ, но я хочу добавить это:
Быстрое решение с использованием ванильного Python, которое также заботится о
sample_num
столбце в примере OP. В моем большом наборе данных с более чем 10 миллионами строк и результатом с 28 миллионами строк это занимает всего около 38 секунд. Принятое решение полностью ломается с таким количеством данных и приводит к тому, чтоmemory error
в моей системе имеется 128 ГБ ОЗУ.источник
Также очень поздно, но вот ответ от Karvy1, который хорошо сработал для меня, если у вас нет панд> = версия 0.25: https://stackoverflow.com/a/52511166/10740287
Для приведенного выше примера вы можете написать:
Тест скорости:
1,33 мс ± 74,8 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, 1000 циклов в каждом)
4,9 мс ± 189 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, по 100 циклов в каждом)
1,38 мс ± 25 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, 1000 циклов в каждом)
источник
Попробуйте это в pandas> = 0.25 версия
источник
.str.split(',')
потому чтоPrices
это уже список.