Один из столбцов в моем фрейме данных pandas содержит список. И я хочу расширить его и преобразовать вертикальную форму, как показано ниже. Как это сделать?
Перед ( код):
import pandas as pd
pd.DataFrame({
'col1':['fruit', 'veicle', 'animal'],
'col2':['apple', 'bycicle', 'cat'],
'col3':[1,4,2],
'list':[
[10, 20],
[1.2, 3.0, 2.75],
['tommy', 'tom']
]
})
Перед (таблица) :
|col1 |col2 |col3|list |
|------|-------|----|----------------|
|fruit |apple | 1|[10, 20] |
|veicle|bicycle| 4|[1.2, 3.0, 2.75]|
|animal|cat | 2|['tommy', 'tom']|
После
|col1 |col2 |col3|list |
|------|-------|----|-------|
|fruit |apple | 1|10 |
|fruit |apple | 1|20 |
|viecle|bycicle| 4|1.2 |
|viecle|bycicle| 4|3.0 |
|viecle|bycicle| 4|2.75 |
|animal|cat | 2|'tommy'|
|animal|cat | 2|'tom |
Примечание 1: длина и тип списков разные.
Примечание 2: я могу NOI изменить код для создания фрейма данных.
Спасибо за чтение.
3 ответа
Узнал этот крутой трюк от piR на днях, используя np.repeat
и np.concatenate
:
idx = np.arange(len(df)).repeat(df.list.str.len(), 0)
out = df.iloc[idx, :-1].assign(list=np.concatenate(df.list.values))
print(out)
col1 col2 col3 list
0 fruit apple 1 10
0 fruit apple 1 20
1 veicle bycicle 4 1.2
1 veicle bycicle 4 3.0
1 veicle bycicle 4 2.75
2 animal cat 2 tommy
2 animal cat 2 tom
Производительность
Небольшой
# Bharath
%timeit df.set_index(['col1','col2','col3']['list'].apply(pd.Series).stack()\
.reset_index().drop('level_3',axis=1)
100 loops, best of 3: 7.75 ms per loop
# Mine
%%timeit
idx = np.arange(len(df)).repeat(df.list.str.len(), 0)
out = df.iloc[idx, :-1].assign(list=np.concatenate(df.list.values))
1000 loops, best of 3: 1.41 ms per loop
Большой
df_test = pd.concat([df] * 10000)
# Bharath
%timeit df_test.set_index(['col1','col2','col3'])['list'].apply(pd.Series).stack()\
.reset_index().drop('level_3',axis=1)
1 loop, best of 3: 7.09 s per loop
# Mine
%%timeit
idx = np.arange(len(df_test)).repeat(df_test.list.str.len(), 0)
out = df_test.iloc[idx, :-1].assign(list=np.concatenate(df_test.list.values))
10 loops, best of 3: 123 ms per loop
Ответ Бхарата на 1 строчку короткий, но медленный. Вот улучшение, которое использует конструктор dataframe вместо df.apply
для ускорения больших данных в 200 раз:
idx = df.set_index(['col1', 'col2', 'col3']).index
out = pd.DataFrame(df.list.values.tolist(), index=idx).stack()\
.reset_index().drop('level_3', 1).rename(columns={0 : 'list'})
print(out)
col1 col2 col3 list
0 fruit apple 1 10
1 fruit apple 1 20
2 veicle bycicle 4 1.2
3 veicle bycicle 4 3
4 veicle bycicle 4 2.75
5 animal cat 2 tommy
6 animal cat 2 tom
Небольшой
100 loops, best of 3: 4.7 ms per loop
Большой
10 loops, best of 3: 28.9 ms per loop
Вот примерно, как вы можете выполнить эту задачу. Это не точное решение, но даст вам представление о том, как вы выполняете свою задачу:
original_df = <your dataframe to start>
new_empty_df = pd.DataFrame()
# now go through each row of the original df
for i in range(original_df.shape[0]):
row_Series = original_df.iloc[i]
row_list = row_Series['list']
for item in row_list:
new_empty_df.append({'col1':row_Series['col1'],
'col2':row_Series['col2'],
'list':item})
Вы можете установить_индекс первых трех столбцов, а затем применить pd.Series
к столбцу списка и затем сложить их.
df.set_index(['col1','col2','col3'])['list'].apply(pd.Series).stack().reset_index().drop('level_3',axis=1)
Выход:
col1 col2 col3 0 0 fruit apple 1 10 1 fruit apple 1 20 2 veicle bycicle 4 1.2 3 veicle bycicle 4 3 4 veicle bycicle 4 2.75 5 animal cat 2 tommy 6 animal cat 2 tom
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.