Создайте фрейм данных Pandas, добавляя по одной строке за раз

avatar
PhE
23 мая 2012 в 08:12
1873029
31
1175

Я понимаю, что Pandas предназначен для загрузки полностью заполненного DataFrame, но мне нужно создать пустой DataFrame, а затем добавлять строки по одной . Как лучше всего это сделать?

Я успешно создал пустой DataFrame с:

res = DataFrame(columns=('lib', 'qty1', 'qty2'))

Затем я могу добавить новую строку и заполнить поле:

res = res.set_value(len(res), 'qty1', 10.0)

Это работает, но кажется очень странным: - / (Не удается добавить строковое значение.)

Как добавить новую строку в мой DataFrame (с другим типом столбцов)?

Источник
Wes McKinney
23 мая 2012 в 13:46
79

Обратите внимание, что это очень неэффективный способ создания большого DataFrame; при добавлении строки должны быть созданы новые массивы (копируя существующие данные).

max
28 августа 2012 в 04:27
6

@WesMcKinney: Спасибо, это действительно полезно знать. Насколько быстро добавить столбцы в огромные таблицы?

user1154664
19 апреля 2013 в 19:54
5

Если это слишком неэффективно для вас, вы можете предварительно выделить дополнительную строку, а затем обновить ее.

cs95
13 июля 2020 в 12:52
24

Привет, ты ... да, , ты ... Я понимаю, что ты задумал ... ты хочешь запустить это внутри цикла и итеративно добавлять строки в пустой DataFrame, не так ли. .. ну не надо!

Giuseppe Salvatore
20 ноября 2020 в 17:24
2

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

justhalf
14 декабря 2020 в 02:49
1

@Giuseppe, тогда pandas DataFrame не является правильной структурой данных, поскольку он предназначен для анализа, а не для обработки в реальном времени.

Giuseppe Salvatore
20 января 2021 в 13:17
0

Спасибо @justhalf, я думаю, это из-за того, как он реализован, он не подходит для таких сценариев. Покопавшись, я нашел это matthewrocklin.com/blog/work/2017/10/16/streaming-dataframes-1, я не уверен, что это правильное решение, но я обязательно попробую

Ответы (31)

avatar
fred
22 июля 2014 в 13:10
796

Вы можете использовать df.loc[i], где строка с индексом i будет тем, что вы указали в фрейме данных.

>>> import pandas as pd
>>> from numpy.random import randint

>>> df = pd.DataFrame(columns=['lib', 'qty1', 'qty2'])
>>> for i in range(5):
>>>     df.loc[i] = ['name' + str(i)] + list(randint(10, size=2))

>>> df
     lib qty1 qty2
0  name0    3    3
1  name1    2    4
2  name2    2    8
3  name3    2    1
4  name4    9    6
FooBar
23 июля 2014 в 14:22
34

Рассмотрите возможность добавления индекса для предварительного выделения памяти (см. Мой ответ)

hobs
25 сентября 2015 в 23:21
58

.loc ссылается на столбец индекса, поэтому, если вы работаете с уже существующим DataFrame с индексом, который не является непрерывной последовательностью целых чисел, начинающейся с 0 (как в вашем примере), .loc перезапишет существующие строки , или вставьте строки, или создайте пробелы в вашем индексе. Более надежный (но не надежный) подход к добавлению существующего фрейма данных ненулевой длины: df.loc[df.index.max() + 1] = [randint(... или предварительное заполнение индекса, как предлагает @FooBar.

flow2k
24 апреля 2019 в 01:30
5

@hobs df.index.max() - это nan, когда DataFrame пуст.

hobs
24 апреля 2019 в 21:31
2

@ flow2k хороший улов! Единственное решение, о котором я могу думать, - это попытка принять (только при вставке первой строки) с вызовом конструктора pd.DataFrame (). Вы знаете способы получше?

flow2k
25 апреля 2019 в 21:17
13

@hobs Одно из решений, которое я придумал, - использовать тернарный оператор: df.loc[0 if pd.isnull(df.index.max()) else df.index.max() + 1]

StackG
11 августа 2020 в 08:20
1

df.loc[i, "column_name"] = new_value также заполнит определенное поле, если вам просто нужно заполнить последнее значение столбца, чтобы выполнялась другая операция (например, для построения .cumsum())

alex
17 марта 2021 в 08:45
0

df.loc [len (df.index)] = строка

avatar
Joaquim
25 июня 2021 в 07:25
-1

Этот фрагмент кода использует список словарей для обновления фрейма данных. Он дополняет ответы ШихарДуа и Михаила Сэма.

import pandas as pd
colour = ["red", "big", "tasty"]
fruits = ["apple", "banana", "cherry"]
dict1={}
feat_list=[]
for x in colour:
    for y in fruits:
#         print(x, y)
        dict1 = dict([('x',x),('y',y)])
#         print(f'dict 1 {dict1}')
        feat_list.append(dict1)
#         print(f'feat_list {feat_list}')
feat_df=pd.DataFrame(feat_list)
feat_df.to_csv('feat1.csv')
avatar
Prajot Kuvalekar
6 марта 2021 в 13:53
7

Если вы всегда хотите добавлять новую строку в конце, используйте это:

df.loc[len(df)] = ['name5', 9, 0]
avatar
Mahdi
21 декабря 2020 в 09:57
0

Если у вас есть фрейм данных df и вы хотите добавить список new_list в качестве новой строки в df, вы можете просто сделать:

df.loc[len(df)] = new_list

Если вы хотите добавить новый фрейм данных new_df под фрейм данных df, вы можете использовать:

df.append(new_df)
avatar
Gerard
11 октября 2020 в 18:46
0

Если все данные в вашем Dataframe имеют один и тот же dtype, вы можете использовать массив NumPy. Вы можете записывать строки прямо в предопределенный массив и преобразовывать его в конце в фрейм данных. Кажется, это даже быстрее, чем преобразование списка диктовок.

import pandas as pd
import numpy as np
from string import ascii_uppercase

startTime = time.perf_counter()
numcols, numrows = 5, 10000
npdf = np.ones((numrows, numcols))
for row in range(numrows):
    npdf[row, 0:] = np.random.randint(0, 100, (1, numcols))
df5 = pd.DataFrame(npdf, columns=list(ascii_uppercase[:numcols]))
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df5.shape)
Peter Mortensen
14 июля 2021 в 10:25
0

По «Кажется, это даже быстрее» : Можете ли вы дать количественную оценку (отредактировав (изменив) свой ответ)? О каком порядке идет речь? На 10% быстрее? На 100% быстрее? В 10 раз быстрее? В 1000000 раз быстрее? В каком масштабе (может быть квадратичным / экспоненциальным)?

avatar
cs95
4 июля 2020 в 22:15
186

НИКОГДА не увеличивайте DataFrame!

Да, люди уже объяснили, что вам НИКОГДА не следует увеличивать DataFrame, и что вы должны добавить свои данные в список и преобразовать его в DataFrame один раз в конце. Но понимаете почему?

Вот самые важные причины, взятые из моего сообщения здесь.

  1. Всегда дешевле / быстрее добавить в список и создать DataFrame за один раз.
  2. Списки занимают меньше памяти и представляют собой гораздо более легкую структуру данных для работы, добавления и удаления.
  3. dtypes автоматически выводятся для ваших данных. С другой стороны, создание пустого фрейма NaN автоматически сделает их object, что плохо.
  4. Индекс создается для вас автоматически, вместо того, чтобы вам нужно было присваивать правильный индекс добавляемой строке.

Это правильный путь ™ для накопления ваших данных

data = []
for a, b, c in some_function_that_yields_data():
    data.append([a, b, c])

df = pd.DataFrame(data, columns=['A', 'B', 'C'])

Эти варианты ужасны

  1. append или concat внутри цикла

    append и concat по своей сути неплохие по отдельности . В проблема начинается, когда вы итеративно вызываете их внутри цикла - это приводит к квадратичному использованию памяти.

    # Creates empty DataFrame and appends
    df = pd.DataFrame(columns=['A', 'B', 'C'])
    for a, b, c in some_function_that_yields_data():
        df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True)  
        # This is equally bad:
        # df = pd.concat(
        #       [df, pd.Series({'A': i, 'B': b, 'C': c})], 
        #       ignore_index=True)
    
  2. Пустой фрейм данных для NaN

    Никогда не создавайте DataFrame из NaN, поскольку столбцы инициализируются с помощью object (медленный, не векторизуемый dtype).

    # Creates DataFrame of NaNs and overwrites values.
    df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
    for a, b, c in some_function_that_yields_data():
        df.loc[len(df)] = [a, b, c]
    

Доказательство в пудинге

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

enter image description here ​​

Код сравнительного анализа для справки.


Подобные сообщения напоминают мне, почему я являюсь частью этого сообщества. Люди понимают важность обучения людей получению правильного ответа с помощью кода правильного , а не правильного ответа с помощью кода неправильного . Теперь вы можете возразить, что не проблема использовать loc или append, если вы добавляете только одну строку в свой DataFrame. Однако люди часто обращаются к этому вопросу, чтобы добавить больше, чем просто одну строку - часто требуется итеративное добавление строки внутри цикла с использованием данных, поступающих из функции (см. связанный вопрос). В этом случае важно понимать, что итеративное наращивание DataFrame - не лучшая идея.

user1657853
8 сентября 2020 в 15:52
5

Справедливо. Есть ли какое-то решение, если вам нужен (или вы хотите) фрейм данных, но все ваши образцы действительно приходят один за другим? (Обычно онлайн-обучение или активное обучение)

Dev Aggarwal
17 сентября 2020 в 10:45
0

Это не влияет на тот случай, когда фрейм данных нужен после каждого append (). В этом случае фрейм данных все равно копируется, поэтому метод df.loc работает быстрее.

cs95
17 сентября 2020 в 16:36
0

@DevAggarwal неверно, loc также каждый раз создает копию. Пожалуйста, посмотрите график времени в моем ответе. Append и loc_append одинаково плохи. Я также поделился своим кодом и процессом, так что вы можете убедиться в этом сами.

Dev Aggarwal
17 сентября 2020 в 17:10
0

Аплогии должны были быть яснее. Пожалуйста, создайте фрейм данных из промежуточного списка внутри цикла for, здесь - gist.github.com/Coldsp33d/…

Kuzeko
19 января 2021 в 17:42
0

Кто-нибудь сравнивал то, что предлагает @DevAggarwal? Я часто дохожу до этого случая

cs95
19 января 2021 в 17:45
0

@Kuzeko, график в моем ответе показывает, что они примерно одинаковы с точки зрения производительности, одинаково плохи, поэтому я бы не стал особо рекомендовать одно перед другим. Если в вашем случае требуется Dataframe на каждой итерации, возможно, вам следует подумать о переосмыслении структуры вашего кода. Может быть, использовать карту или применить.

Kuzeko
20 января 2021 в 15:11
0

Большое спасибо за ответ. Я провел небольшой тест, адаптируя ваш код к моим данным, и все же кажется лучше, что метод добавления списка, даже несмотря на то, что преимущество уменьшается. К сожалению, мне нужно передать его сторонним библиотекам, поэтому мне нужно создать этот фрейм данных.

Wang
13 июня 2021 в 20:30
0

ну, большая часть фреймов данных слишком велика и не может быть сохранена в ОЗУ, так что все равно неплохо увеличить их, если у вас есть хранилище фреймов данных на диске, таком как HDFStore и т. д.

avatar
Harshal Deore
13 июня 2020 в 15:09
2
initial_data = {'lib': np.array([1,2,3,4]), 'qty1': [1,2,3,4], 'qty2': [1,2,3,4]}

df = pd.DataFrame(initial_data)

df

lib    qty1    qty2
0    1    1    1
1    2    2    2
2    3    3    3
3    4    4    4

val_1 = [10]
val_2 = [14]
val_3 = [20]

df.append(pd.DataFrame({'lib': val_1, 'qty1': val_2, 'qty2': val_3}))

lib    qty1    qty2
0    1    1    1
1    2    2    2
2    3    3    3
3    4    4    4
0    10    14    20

Вы можете использовать цикл для для перебора значений или добавления массивов значений.

val_1 = [10, 11, 12, 13]
val_2 = [14, 15, 16, 17]
val_3 = [20, 21, 22, 43]

df.append(pd.DataFrame({'lib': val_1, 'qty1': val_2, 'qty2': val_3}))

lib    qty1    qty2
0    1    1    1
1    2    2    2
2    3    3    3
3    4    4    4
0    10    14    20
1    11    15    21
2    12    16    22
3    13    17    43
Peter Mortensen
14 июля 2021 в 10:14
0

Пояснение к первой части было бы в порядке. И почему в примере кода нет цикла for, когда о нем говорят? Вы можете прояснить это? Пожалуйста, ответьте, отредактировав свой ответ, а не здесь, в комментариях ( без «Изменить:», «Обновить:» или аналогичные - ответ должен выглядеть так, как если бы он был написан сегодня).

avatar
Giorgos Myrianthous
1 мая 2020 в 14:39
3

Все, что вам нужно, это loc[df.shape[0]] или loc[len(df)]


# Assuming your df has 4 columns (str, int, str, bool)
df.loc[df.shape[0]] = ['col1Value', 100, 'col3Value', False] 

или

df.loc[len(df)] = ['col1Value', 100, 'col3Value', False] 
avatar
hansrajswapnil
30 апреля 2020 в 14:07
1

Для этого вы можете объединить два DataFrames. Я в основном столкнулся с этой проблемой, чтобы добавить новую строку в существующий DataFrame с символьным индексом (не числовым).

Итак, я ввожу данные для новой строки в канал () и индекс в списке.

new_dict = {put input for new row here}
new_list = [put your index here]

new_df = pd.DataFrame(data=new_dict, index=new_list)

df = pd.concat([existing_df, new_df])
avatar
srikanth Gattu
17 апреля 2020 в 17:54
-1

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

Эта идея заставляет меня написать следующий код.

df2 = df.to_dict()
values = ["s_101", "hyderabad", 10, 20, 16, 13, 15, 12, 12, 13, 25, 26, 25, 27, "good", "bad"] # This is the total row that we are going to add
i = 0
for x in df.columns:   # Here df.columns gives us the main dictionary key
    df2[x][101] = values[i]   # Here the 101 is our index number. It is also the key of the sub dictionary
    i += 1
avatar
Shahir Ansari
26 марта 2020 в 14:09
4

Если вы хотите добавить строку в конце, добавьте ее в виде списка:

valuestoappend = [va1, val2, val3]
res = res.append(pd.Series(valuestoappend, index = ['lib', 'qty1', 'qty2']), ignore_index = True)
avatar
kamran kausar
19 февраля 2020 в 06:35
0

pandas.DataFrame.append

DataFrame.append (self, other, ignore_index = False, verify_integrity = False, sort = False) → 'DataFrame'

Код

df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
df.append(df2)

Если для ignore_index установлено значение True:

df.append(df2, ignore_index=True)
Peter Mortensen
14 июля 2021 в 10:05
0

Непонятно, почему первые две строки не являются буквальным кодом. Краткость - это хорошо, но не могли бы вы уточнить в своем ответе, например добавив вспомогательный текст? Но без «Изменить:», «Обновить:» и т.п. - ответ должен выглядеть так, как если бы он был написан сегодня.

avatar
qwr
30 декабря 2019 в 01:35
7

Вместо списка словарей, как в ответе Шихардуа, мы также можем представить нашу таблицу в виде словаря списков , где каждый список хранит один столбец в порядке строк, учитывая мы заранее знаем наши столбцы. В конце мы создаем DataFrame один раз.

Для столбцов c и строк n используется один словарь и c списки вместо одного списка и <4049167528167528> словарей7 <4049> n <4049> dictionaries7 Метод list-of-dictionaries содержит каждый словарь, в котором хранятся все ключи, и требует создания нового словаря для каждой строки. Здесь мы добавляем только к спискам, что является постоянным по времени и теоретически очень быстро.

# Current data
data = {"Animal":["cow", "horse"], "Color":["blue", "red"]}

# Adding a new row (be careful to ensure every column gets another value)
data["Animal"].append("mouse")
data["Color"].append("black")

# At the end, construct our DataFrame
df = pd.DataFrame(data)
#   Animal  Color
# 0    cow   blue
# 1  horse    red
# 2  mouse  black
avatar
RockStar
21 октября 2019 в 07:26
10

Вы можете использовать объект-генератор для создания Dataframe, который будет более эффективно использовать память по сравнению со списком.

num = 10

# Generator function to generate generator object
def numgen_func(num):
    for i in range(num):
        yield ('name_{}'.format(i), (i*i), (i*i*i))

# Generator expression to generate generator object (Only once data get populated, can not be re used)
numgen_expression = (('name_{}'.format(i), (i*i), (i*i*i)) for i in range(num) )

df = pd.DataFrame(data=numgen_func(num), columns=('lib', 'qty1', 'qty2'))

Чтобы добавить необработанные данные в существующий DataFrame, вы можете использовать метод добавления.

df = df.append([{ 'lib': "name_20", 'qty1': 20, 'qty2': 400  }])
avatar
Armali
22 августа 2019 в 12:39
0

Мы часто видим конструкцию df.loc[subscript] = … для назначения одной строке DataFrame. Михаил_Сам опубликовал тесты, содержащие, среди прочего, эту конструкцию, а также метод, использующий dict и создающий DataFrame в конце . Он обнаружил, что последний на сегодняшний день самый быстрый.

Но если мы заменим df3.loc[i] = … (с предварительно выделенным DataFrame) в его коде на df3.values[i] = …, результат значительно изменится, поскольку этот метод работает аналогично тому, который использует dict. Поэтому мы должны чаще принимать во внимание использование df.values[subscript] = …. Однако обратите внимание, что .values принимает нижний индекс, отсчитываемый от нуля, который может отличаться от DataFrame.index.

Armali
7 февраля 2020 в 10:23
1

@baxx - Один пример кода находится по ссылке тестов (# .loc with prealloc), другой пример находится в вопросе Мне нужно сравнить данные из каждой строки DataFrame Pandas с данными из остальных строк, есть ли способ ускорить вычисление? и принятый ответ.

avatar
shivampip
5 сентября 2018 в 19:30
7

Вот способ добавить / добавить строку в пандах DataFrame:

def add_row(df, row):
    df.loc[-1] = row
    df.index = df.index + 1
    return df.sort_index()

add_row(df, [1,2,3])

Его можно использовать для вставки / добавления строки в пустой или заполненный фрейм данных Pandas.

Parthiban Rajendran
13 октября 2018 в 17:33
1

это добавление с индексом в порядке убывания

avatar
Qinsi
30 августа 2018 в 03:19
16

Я придумал простой и приятный способ:

>>> df
     A  B  C
one  1  2  3
>>> df.loc["two"] = [4,5,6]
>>> df
     A  B  C
one  1  2  3
two  4  5  6

Обратите внимание на предупреждение о производительности, как указано в комментариях.

waterproof
25 июля 2019 в 16:43
2

Обратите внимание, что это скопирует весь DataFrame под капотом. Базовые массивы не могут быть расширены, поэтому их нужно скопировать.

avatar
Mikhail_Sam
26 декабря 2017 в 14:02
322

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

Производительность

  1. Использование .append (ответ NPE)
  2. Использование .loc (ответ Фреда)
  3. Использование .loc с предварительным выделением (ответ FooBar)
  4. Использование dict и создание DataFrame в конце (ответ ShikharDua)

Результаты выполнения (в секундах):

Подход 1000 строк 5000 строк 10 000 строк
.append 0,69 3,39 6,78
.loc без предварительного выделения 0,74 3,90 8,35
.loc с предварительным выделением 0,24 2,58 8,70
dict 0,012 0,046 0,084

Поэтому я использую сложение через словарь для себя.


Код:

import pandas as pd
import numpy as np
import time

del df1, df2, df3, df4
numOfRows = 1000
# append
startTime = time.perf_counter()
df1 = pd.DataFrame(np.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows-4):
    df1 = df1.append( dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E']), ignore_index=True)
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df1.shape)

# .loc w/o prealloc
startTime = time.perf_counter()
df2 = pd.DataFrame(np.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows):
    df2.loc[i]  = np.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df2.shape)

# .loc with prealloc
df3 = pd.DataFrame(index=np.arange(0, numOfRows), columns=['A', 'B', 'C', 'D', 'E'] )
startTime = time.perf_counter()
for i in range( 1,numOfRows):
    df3.loc[i]  = np.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df3.shape)

# dict
startTime = time.perf_counter()
row_list = []
for i in range (0,5):
    row_list.append(dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E']))
for i in range( 1,numOfRows-4):
    dict1 = dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E'])
    row_list.append(dict1)

df4 = pd.DataFrame(row_list, columns=['A','B','C','D','E'])
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df4.shape)

P.S .: Я считаю, что моя реализация не идеальна, и, возможно, есть некоторая оптимизация, которую можно было бы сделать.

krassowski
23 января 2019 в 20:44
5

Использование df2.index.max() для .loc излишне увеличивает вычислительную сложность. Подойдет простой df2.loc[i] = .... Для меня это уменьшило время с 10 до 8,64 с.

FooBar
29 июля 2019 в 18:27
0

Пожалуйста, удалите мое имя из списка, поскольку вы не следуете моему подходу в своем тесте: вы не распределяете память заранее, предоставляя индекс подходящего размера.

Mikhail_Sam
30 июля 2019 в 08:17
0

@FooBar Привет! Рад, что вы как автор увидели мой ответ :) вы правы, я упустил этот важный момент. Я предпочитаю добавить еще одну строку для моей таблицы результатов, так как ваш подход показывает другой результат!

FabioSpaghetti
11 августа 2019 в 12:36
0

@Mikhail_Sam Как бы вы использовали сводную таблицу, чтобы записать ее в файл Excel, используя самый быстрый метод, dict?

rayzinnz
12 августа 2019 в 08:33
0

Зачем использовать список dicts вместо того, чтобы просто складывать numpy в 2D-массив и преобразовывать и добавлять имена столбцов в конце?

Mikhail_Sam
16 августа 2019 в 08:53
0

@FabioSpaghetti в dict-методах мы получаем df в ens. Так же, как и во всех остальных методах. Таким образом, нет никаких проблем с созданием на нем сводной таблицы. Вот, например, пример чтения / записи в Excel: сводные таблицы в Excel

flow2k
29 сентября 2019 в 09:03
1

@Mikhail_Sam Что касается последнего, диктованного подхода, каково обоснование использования двух циклов, for i in range (0,5): и for i in range( 1,numOfRows-4):?

trumpetlicks
4 декабря 2019 в 14:23
1

Просто хотел выкинуть еще один комментарий о том, почему Dict to Pandas DataFrame - лучший способ. В моих экспериментах с набором данных, который имеет несколько разных типов данных в таблице, использование методов добавления Pandas уничтожает типизацию, тогда как использование Dict и создание из него DataFrame только ОДИН РАЗ, кажется, сохраняет исходные типы данных нетронутыми.

qwr
30 декабря 2019 в 01:45
0

У меня есть другой метод, который должен быть сопоставим со словарным методом, но может быть немного быстрее, чем вы должны попробовать время. coderhelper.com/a/59524806/3163618

qwr
30 декабря 2019 в 01:56
0

Я тестировал его, и он немного быстрее: list-of-dicts: 1000: 0,034, 5000: 0,155, 10000: 0,342. список-списков: 1000: 0,032, 5000: 0,149, 10000: 0,295

Sumit Pokhrel
3 марта 2020 в 22:10
0

Я пробовал это в своем коде, используя Tuple, и он даже быстрее, чем Dict. Просто интересно, что кортежи неизменны. Итак, как мы можем их добавить?

Mikhail_Sam
5 июня 2020 в 07:30
0

@rayzinnz Я не пробовал, но полагаю, что это не должно быть быстрее - массивы numpy представляют собой непрерывные части памяти, поэтому numpy воссоздает массив каждый раз, когда вы используете htack. Пока в список просто добавляем указатель на новую переменную в другом месте памяти.

EricLavault
18 октября 2020 в 13:42
0

Я думаю, что подход dict следует переименовать в подход list.appendappend в df.append), он быстрее, потому что он полагается на список row_list.append(), а затем создает фрейм данных из этого списка вместо добавления данных непосредственно во фрейме данных с помощью df1.append(). Оба метода используют словари, точка использует list() против pd.DataFrame() при заполнении данных строка за строкой.

avatar
tomatom
13 октября 2017 в 17:48
-3

Это позаботится о добавлении элемента в пустой DataFrame. Проблема в том, что df.index.max() == nan для первого индекса:

df = pd.DataFrame(columns=['timeMS', 'accelX', 'accelY', 'accelZ', 'gyroX', 'gyroY', 'gyroZ'])

df.loc[0 if math.isnan(df.index.max()) else df.index.max() + 1] = [x for x in range(7)]
avatar
Brian Burns
13 октября 2017 в 12:16
33

Вы также можете создать список списков и преобразовать его в фрейм данных -

import pandas as pd

columns = ['i','double','square']
rows = []

for i in range(6):
    row = [i, i*2, i*i]
    rows.append(row)

df = pd.DataFrame(rows, columns=columns)

давая

    i   double  square
0   0   0   0
1   1   2   1
2   2   4   4
3   3   6   9
4   4   8   16
5   5   10  25
avatar
Vineet Jain
25 августа 2017 в 15:47
1

Сделайте это просто. Взяв список в качестве входных данных, который будет добавлен в виде строки в кадре данных:

import pandas as pd
res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
for i in range(5):
    res_list = list(map(int, input().split()))
    res = res.append(pd.Series(res_list, index=['lib', 'qty1', 'qty2']), ignore_index=True)
avatar
hkyi
6 августа 2017 в 05:06
47

Ради питоновского пути:

res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
res = res.append([{'qty1':10.0}], ignore_index=True)
print(res.head())

   lib  qty1  qty2
0  NaN  10.0   NaN
avatar
qed
11 ноября 2016 в 18:18
3

Другой способ сделать это (вероятно, не очень эффективный):

# add a row
def add_row(df, row):
    colnames = list(df.columns)
    ncol = len(colnames)
    assert ncol == len(row), "Length of row must be the same as width of DataFrame: %s" % row
    return df.append(pd.DataFrame([row], columns=colnames))

Вы также можете улучшить класс DataFrame следующим образом:

import pandas as pd
def add_row(self, row):
    self.loc[len(self.index)] = row
pd.DataFrame.add_row = add_row
avatar
Jack Daniel
18 июля 2016 в 09:54
8

Создайте новую запись (фрейм данных) и добавьте в old_data_frame .

Передайте список значений и соответствующие имена столбца , чтобы создать new_record (data_frame):

new_record = pd.DataFrame([[0, 'abcd', 0, 1, 123]], columns=['a', 'b', 'c', 'd', 'e'])

old_data_frame = pd.concat([old_data_frame, new_record])
avatar
user3250815
13 июля 2016 в 09:49
14

Это не ответ на вопрос OP, а игрушечный пример для иллюстрации ответа ШихарДуа, который я нашел очень полезным.

Хотя этот фрагмент тривиален, в реальных данных у меня было 1000 строк и много столбцов, и я хотел иметь возможность группировать по разным столбцам, а затем выполнять статистику ниже для более чем одного целевого столбца. Поэтому наличие надежного метода построения фрейма данных по одной строке за раз было большим удобством. Спасибо ShikharDua!

import pandas as pd

BaseData = pd.DataFrame({ 'Customer' : ['Acme','Mega','Acme','Acme','Mega','Acme'],
                          'Territory'  : ['West','East','South','West','East','South'],
                          'Product'  : ['Econ','Luxe','Econ','Std','Std','Econ']})
BaseData

columns = ['Customer','Num Unique Products', 'List Unique Products']

rows_list=[]
for name, group in BaseData.groupby('Customer'):
    RecordtoAdd={} #initialise an empty dict
    RecordtoAdd.update({'Customer' : name}) #
    RecordtoAdd.update({'Num Unique Products' : len(pd.unique(group['Product']))})
    RecordtoAdd.update({'List Unique Products' : pd.unique(group['Product'])})

    rows_list.append(RecordtoAdd)

AnalysedData = pd.DataFrame(rows_list)

print('Base Data : \n',BaseData,'\n\n Analysed Data : \n',AnalysedData)
avatar
W.P. McNeill
23 февраля 2016 в 16:43
78

Вы можете добавить одну строку в качестве словаря, используя параметр ignore_index.

>>> f = pandas.DataFrame(data = {'Animal':['cow','horse'], 'Color':['blue', 'red']})
>>> f
  Animal Color
0    cow  blue
1  horse   red
>>> f.append({'Animal':'mouse', 'Color':'black'}, ignore_index=True)
  Animal  Color
0    cow   blue
1  horse    red
2  mouse  black
Blairg23
28 мая 2016 в 03:57
46

Вы также можете упомянуть, что f.append(<stuff>) создает новый объект, а не просто добавляется к текущему объекту на месте, поэтому, если вы пытаетесь добавить к кадру данных в скрипте, вам нужно сказать f = f.append(<stuff>)

lol
8 ноября 2016 в 03:48
2

есть ли способ сделать это на месте?

waterproof
25 июля 2019 в 16:42
0

@хах нет. см. github.com/pandas-dev/pandas/issues/2801 - базовые массивы не могут быть расширены, поэтому их нужно копировать.

Gene M
31 июля 2020 в 21:45
1

Я предпочитаю этот метод, потому что он очень похож на SQL (семантически не зависит от индексов), и я использую его, когда это возможно.

avatar
Lydia
24 июня 2015 в 21:06
90
mycolumns = ['A', 'B']
df = pd.DataFrame(columns=mycolumns)
rows = [[1,2],[3,4],[5,6]]
for row in rows:
    df.loc[len(df)] = row
jhin
9 марта 2016 в 00:00
3

Этот! Я долго искал, и это первый пост, который действительно показывает, как присваивать определенные значения строке! Дополнительный вопрос: каков синтаксис для пар "имя-столбец / значение"? Я предполагаю, что это должно быть что-то, использующее диктатор, но я не могу понять это правильно.

waterproof
25 июля 2019 в 16:42
7

это неэффективно, поскольку фактически копирует весь DataFrame при его расширении.

avatar
FooBar
23 июля 2014 в 14:21
123

Если вы заранее знаете количество записей, вам следует предварительно выделить пространство, также указав индекс (взяв пример данных из другого ответа):

import pandas as pd
import numpy as np
# we know we're gonna have 5 rows of data
numberOfRows = 5
# create dataframe
df = pd.DataFrame(index=np.arange(0, numberOfRows), columns=('lib', 'qty1', 'qty2') )

# now fill it up row by row
for x in np.arange(0, numberOfRows):
    #loc or iloc both work here since the index is natural numbers
    df.loc[x] = [np.random.randint(-1,1) for n in range(3)]
In[23]: df
Out[23]: 
   lib  qty1  qty2
0   -1    -1    -1
1    0     0     0
2   -1     0    -1
3    0    -1     0
4   -1     0     0

Сравнение скорости

In[30]: %timeit tryThis() # function wrapper for this answer
In[31]: %timeit tryOther() # function wrapper without index (see, for example, @fred)
1000 loops, best of 3: 1.23 ms per loop
100 loops, best of 3: 2.31 ms per loop

И - как из комментариев - при размере 6000 разница в скорости становится еще больше:

Увеличение размера массива (12) и количества строк (500) делает разница в скорости более разительна: 313 мс против 2,29 с

ely
9 октября 2014 в 18:32
4

Отличный ответ. Это должно быть нормой, чтобы пространство строки не распределялось постепенно.

Tickon
2 апреля 2015 в 10:55
9

Увеличение размера массива (12) и количества строк (500) делает разницу в скорости более заметной: 313 мс против 2,29 с.

avatar
Nasser Al-Wohaibi
30 апреля 2014 в 17:31
75

Для эффективного добавления см. Как добавить дополнительную строку в фрейм данных pandas и <3880850703> Настройка с увеличением

Добавить строки через loc/ix в несуществующие данные ключевого индекса. Например:

In [1]: se = pd.Series([1,2,3])

In [2]: se
Out[2]:
0    1
1    2
2    3
dtype: int64

In [3]: se[5] = 5.

In [4]: se
Out[4]:
0    1.0
1    2.0
2    3.0
5    5.0
dtype: float64

Или:

In [1]: dfi = pd.DataFrame(np.arange(6).reshape(3,2),
   .....:                 columns=['A','B'])
   .....:

In [2]: dfi
Out[2]:
   A  B
0  0  1
1  2  3
2  4  5

In [3]: dfi.loc[:,'C'] = dfi.loc[:,'A']

In [4]: dfi
Out[4]:
   A  B  C
0  0  1  0
1  2  3  2
2  4  5  4
In [5]: dfi.loc[3] = 5

In [6]: dfi
Out[6]:
   A  B  C
0  0  1  0
1  2  3  2
2  4  5  4
3  5  5  5

Guilherme Felipe Reis
21 февраля 2019 в 15:38
1

Пользователи просили орудие (добавить новую строку). Здесь мы видим, как добавить строку в определенный индекс или добавить столбец.

PirateApp
6 марта 2019 в 17:15
1

любые тесты того, как это работает по сравнению с методом dict

waterproof
25 июля 2019 в 16:41
0

это неэффективно, поскольку фактически копирует весь DataFrame.

avatar
ShikharDua
5 июля 2013 в 20:38
661

Если вы можете получить все данные для фрейма данных заранее, существует гораздо более быстрый подход, чем добавление во фрейм данных:

  1. Создайте список словарей, в котором каждый словарь соответствует строке входных данных.
  2. Создайте фрейм данных из этого списка.

У меня была аналогичная задача, для которой добавление к кадру данных строка за строкой занимало 30 минут, а создание кадра данных из списка словарей выполнялось за секунды.

rows_list = []
for row in input_rows:

        dict1 = {}
        # get input row in dictionary format
        # key = col_name
        dict1.update(blah..) 

        rows_list.append(dict1)

df = pd.DataFrame(rows_list)               
fantabolous
13 августа 2014 в 12:19
65

Я перешел к этому и в любой ситуации, когда я не могу получить все данные заранее. Разница в скорости поразительная.

thikonom
25 декабря 2015 в 22:01
64

Копирование из документов pandas: It is worth noting however, that concat (and therefore append) makes a full copy of the data, and that constantly reusing this function can create a significant performance hit. If you need to use the operation over several datasets, use a list comprehension. (pandas.pydata.org/pandas-docs/stable/…)

user5359531
9 августа 2016 в 21:36
7

Это прекрасно работает! За исключением того, что я создал фрейм данных, имена столбцов были в неправильном порядке ...

ShikharDua
10 августа 2016 в 20:31
5

@ user5359531 В этом случае вы можете использовать заказанный dict

Marcello Grechi Lins
27 января 2017 в 22:26
27

@ user5359531 Вы можете указать столбцы вручную, и порядок будет сохранен. pd.DataFrame (rows_list, columns = ['C1', 'C2', 'C3']) поможет

avg
11 января 2018 в 10:31
2

@ShikharDua Можете ли вы объяснить, как структурировать данные, т.е. когда вы говорите # получить строку ввода в формате словаря # key = col_name, что вы имеете в виду? мой вариант использования: я извлекаю строки из таблицы MySQL, и каждый объект row поступает в виде кортежа, содержащего 10 строк

ShikharDua
29 января 2019 в 00:29
0

@avg Я предполагаю, что каждый кортеж должен быть строкой в ​​таблице pandas. В этом случае это может быть элемент, если row_list вместо dict1. И как только все данные будут представлены в форме [кортеж1, кортеж2, кортеж 3, .....], вы можете создать окончательный набор данных.

Eric Ed Lohmar
17 июня 2019 в 16:10
0

@avg, в этом случае, вероятно, лучше использовать метод read_sql. Тогда вам не нужно беспокоиться о его самостоятельном разборе.

qwr
30 декабря 2019 в 01:16
0

В чем разница в производительности между списком dict (1 dict на строку) и 1 dict с каждым значением в списке? (1 список на столбец)

Sumit Pokhrel
3 марта 2020 в 22:17
1

Я пробовал это в своем коде, используя Tuple, и он даже быстрее, чем Dict. В моем случае для 160 строк и 4 столбцов в 3 раза быстрее.

Josiah Yoder
25 июня 2020 в 17:19
1

@thikonom Разве функция добавления, используемая здесь, не является списком Python (не объектом pandas), который имеет O (1) амортизированный append () в CPython? Мне этот ответ кажется хорошим.

kevin_theinfinityfund
14 июля 2020 в 17:02
1

Почему мы используем dict.update (), а не индексирование, как упомянуто здесь?

ShikharDua
15 июля 2020 в 00:54
0

@ the775 вы можете использовать все, что хотите.

kevin_theinfinityfund
16 июля 2020 в 16:04
0

@ShikharDua ценю это. Я упомянул об этом, потому что в статье I , помеченной выше, упоминается, что время выполнения собственного dict1[key] = value быстрее, чем метод .update (), и многие ответы касаются скорости.

mLstudent33
6 ноября 2020 в 02:47
0

это способ сделать это для существующего фрейма данных путем транспонирования фрейма данных: coderhelper.com/a/29815523/13865853

mLstudent33
6 ноября 2020 в 03:00
0

на самом деле разве не быстрее делать df_dict = df.to_dict('records')? Таким образом, вы получаете словари с именами столбцов, а не с int для номера столбца в качестве ключей.

avatar
NPE
23 мая 2012 в 08:14
323

Вы можете использовать pandas.concat() или DataFrame.append(). Подробнее и примеры см. В разделе Слияние, объединение и объединение.

notilas
20 августа 2014 в 22:52
7

Привет, так каков ответ на методы, использующие append () или concat (). У меня та же проблема, но я все еще пытаюсь ее решить.

jwg
18 мая 2016 в 14:34
142

Это правильный ответ, но не очень хороший ответ (почти только ссылка).

Ken Williams
16 марта 2017 в 16:03
5

Я думаю, что ответ @fred более правильный. IIUC проблема с этим ответом заключается в том, что он без необходимости копирует весь DataFrame каждый раз, когда добавляется строка. Использование механизма .loc, которого можно избежать, особенно если вы будете осторожны.

StayFoolish
8 сентября 2017 в 12:46
7

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