Создание пустой Pandas DataFrame, а затем ее заполнение?

Я начинаю с документов панд на DataFrame здесь: http://pandas.pydata.org/pandas-docs/stable/dsintro.html

Я хотел бы итеративно заполнять DataFrame значениями для расчета временных рядов. В общем, я хотел бы инициализировать DataFrame столбцами A, B и строками отметок времени, все 0 или все NaN.

Затем я добавляю начальные значения и просматриваю эти данные, вычисляя новую строку из row[A][t] = row[A][t-1]+1 строки, скажем, row[A][t] = row[A][t-1]+1 или около того.

В настоящее время я использую код, как показано ниже, но я чувствую себя немного уродливо, и должен быть способ сделать это напрямую с помощью DataFrame, или просто лучше. Примечание: я использую Python 2.7.

import datetime as dt
import pandas as pd
import scipy as s

if __name__ == '__main__':
    base = dt.datetime.today().date()
    dates = [ base - dt.timedelta(days=x) for x in range(0,10) ]
    dates.sort()

    valdict = {}
    symbols = ['A','B', 'C']
    for symb in symbols:
        valdict[symb] = pd.Series( s.zeros( len(dates)), dates )

    for thedate in dates:
        if thedate > dates[0]:
            for symb in valdict:
                valdict[symb][thedate] = 1+valdict[symb][thedate - dt.timedelta(days=1)]

    print valdict

Ответ 1

Вот несколько предложений:

Используйте date_range для индекса:

import datetime
import pandas as pd
import numpy as np

todays_date = datetime.datetime.now().date()
index = pd.date_range(todays_date-datetime.timedelta(10), periods=10, freq='D')

columns = ['A','B', 'C']

Примечание. Мы могли бы создать пустой DataFrame (с NaN s), просто написав:

df_ = pd.DataFrame(index=index, columns=columns)
df_ = df_.fillna(0) # with 0s rather than NaNs

Чтобы выполнить эти типы вычислений для данных, используйте массив numpy:

data = np.array([np.arange(10)]*3).T

Следовательно, мы можем создать DataFrame:

In [10]: df = pd.DataFrame(data, index=index, columns=columns)

In [11]: df
Out[11]: 
            A  B  C
2012-11-29  0  0  0
2012-11-30  1  1  1
2012-12-01  2  2  2
2012-12-02  3  3  3
2012-12-03  4  4  4
2012-12-04  5  5  5
2012-12-05  6  6  6
2012-12-06  7  7  7
2012-12-07  8  8  8
2012-12-08  9  9  9

Ответ 2

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

В этом примере я использую этот pandas doc для создания нового фрейма данных, а затем используя append для записи в newDF с данными из oldDF.


Посмотрите на это

newDF = pd.DataFrame() #creates a new dataframe that empty
newDF = newDF.append(oldDF, ignore_index = True) # ignoring index is optional
# try printing some data from newDF
print newDF.head() #again optional 
  • Если мне придется добавлять новые данные в этот новый DF из более чем один oldDFs, я просто использую цикл for для итерации pandas.DataFrame.append()

Ответ 3

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

import pandas as pd

col_names =  ['A', 'B', 'C']
my_df  = pd.DataFrame(columns = col_names)
my_df

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

my_df.loc[len(my_df)] = [2, 4, 5]

Вы также можете передать словарь:

my_dic = {'A':2, 'B':4, 'C':5}
my_df.loc[len(my_df)] = my_dic 

Однако, если вы хотите добавить другой фрейм данных в my_df, сделайте следующее:

col_names =  ['A', 'B', 'C']
my_df2  = pd.DataFrame(columns = col_names)
my_df = my_df.append(my_df2)

Если вы добавляете строки в цикл, учтите проблемы с производительностью:
Примерно для первых 1000 записей "my_df.loc" производительность лучше, но постепенно она становится медленнее с увеличением количества записей в цикле.

Если вы планируете делать все внутри большого цикла (скажем, 10 миллионов записей или около того):
Вам лучше использовать смесь этих двух; заполняйте фрейм данных iloc, пока размер не достигнет 1000, затем добавьте его к исходному фрейму данных и очистите временный фрейм данных. Это повысит вашу производительность примерно в 10 раз.

Ответ 4

Единственный правильный способ создания DataFrame

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

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

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

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

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

Другое преимущество этого метода заключается в том, что dtypes автоматически выводятся (вместо того, чтобы назначать object всем).

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


То, что вы не должны делать

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

Вот самая большая ошибка, которую я видел от новичков:

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) # yuck
    # or similarly,
    # df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)

Память перераспределяется для каждой concat вас операции append или concat. Соедините это с циклом, и вы получите квадратичную операцию сложности. Если вы мне не верите, прочитайте некоторые комментарии под другими ответами.

По моему опыту, создание фрейма данных необходимого размера, заполненного NaN, а затем заполнение значениями происходит намного-намного медленнее, чем создание фрейма данных [..] и присоединение одного столбца за каждый оборот цикла. Я имею в виду df[col_name] = pandas.Series([...]) в цикле, повторяющем имена столбцов. В первом случае не только выделение памяти занимает много времени, но замена NaN новыми значениями кажется чрезвычайно медленной. - deeenes

Обратите внимание, что append (и аналогично concat) копирует полный набор данных в новый объект каждый раз, следовательно, повторение и добавление может и приведет к значительному снижению производительности. - МустафаАатта

Другая ошибка, связанная с df.append заключается в том, что пользователи склонны забывать, что append не является функцией на месте, поэтому результат должен быть возвращен обратно. Вы также должны беспокоиться о dtypes:

df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)

df.dtypes
A     object   # yuck!
B    float64
C     object
dtype: object

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

df.infer_objects().dtypes
A      int64
B    float64
C     object
dtype: object

loc внутри цикла

Я также видел, что loc используется для добавления в DataFrame, который был создан пустым:

df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
    df.loc[len(df)] = [a, b, c]

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

Пустой фрейм данных NaNs

И затем, создание DataFrame из NaN, и все оговорки, связанные с ним.

df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
     A    B    C
0  NaN  NaN  NaN
1  NaN  NaN  NaN
2  NaN  NaN  NaN
3  NaN  NaN  NaN
4  NaN  NaN  NaN

Он создает DataFrame столбцов объекта, как и другие.

df.dtypes
A    object  # you DON'T want this
B    object
C    object
dtype: object

В приложении есть все проблемы, описанные выше.

for i, (a, b, c) in enumerate(some_function_that_yields_data()):
    df.iloc[i] = [a, b, c]

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

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

enter image description here

Контрольный код для справки.

Ответ 5

Предположим, датафрейм с 19 строками

index=range(0,19)
index

columns=['A']
test = pd.DataFrame(index=index, columns=columns)

Сохранение столбца А в качестве константы

test['A']=10

Сохранение столбца b как переменной, заданной циклом

for x in range(0,19):
    test.loc[[x], 'b'] = pd.Series([x], index = [x])

Вы можете заменить первый x в pd.Series([x], index = [x]) любым значением