Как объединить серию и DataFrame

83

Если вы пришли сюда в поисках информации о том, как объединить a DataFrameи Seriesиндекс , пожалуйста, посмотрите этот ответ .

Первоначальное намерение OP состояло в том, чтобы спросить, как назначить элементы серии в качестве столбцов другому DataFrame . Если вам интересно узнать ответ на этот вопрос, посмотрите на принятый ответ EdChum.


Лучшее, что я могу придумать, это

df = pd.DataFrame({'a':[1, 2], 'b':[3, 4]})  # see EDIT below
s = pd.Series({'s1':5, 's2':6})

for name in s.index:
    df[name] = s[name]

   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

Может ли кто-нибудь предложить лучший синтаксис / более быстрый метод?

Мои попытки:

df.merge(s)
AttributeError: 'Series' object has no attribute 'columns'

и

df.join(s)
ValueError: Other Series must have a name

ИЗМЕНИТЬ Первые два опубликованных ответа выявили проблему с моим вопросом, поэтому, пожалуйста, используйте следующее для построения df:

df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])

с конечным результатом

    a  b  s1  s2
3 NaN  4   5   6
5   2  5   5   6
6   3  6   5   6
Натан Ллойд
источник

Ответы:

26

Вы можете построить фрейм данных из серии, а затем объединить его с фреймом данных. Таким образом, вы указываете данные как значения, но умножаете их на длину, устанавливаете столбцы в индекс и устанавливаете для параметров left_index и right_index значение True:

In [27]:

df.merge(pd.DataFrame(data = [s.values] * len(s), columns = s.index), left_index=True, right_index=True)
Out[27]:
   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

ИЗМЕНИТЬ для ситуации, когда вы хотите, чтобы индекс созданного вами df из серии использовал индекс df, вы можете сделать следующее:

df.merge(pd.DataFrame(data = [s.values] * len(df), columns = s.index, index=df.index), left_index=True, right_index=True)

Предполагается, что индексы соответствуют длине.

EdChum
источник
168

Обновление
Начиная с версии 0.24.0, вы можете объединять DataFrame и Series, пока серия названа.

df.merge(s.rename('new'), left_index=True, right_index=True)
# If series is already named,
# df.merge(s, left_index=True, right_index=True)

В настоящее время вы можете просто преобразовать серию в DataFrame с помощью to_frame () . Итак (если вы присоединяетесь к индексу):

df.merge(s.to_frame(), left_index=True, right_index=True)
Николас Морли
источник
6
Используя определения вопроса dfи s, этот ответ возвращает мне пустой фрейм данных, а не результат, запрошенный в вопросе. Мы не хотим совпадать по индексу; мы хотим транслировать sзначения во все строки df.
CPBL
2
Это решает другую проблему: «учитывая DataFrame и Series, как их можно объединить в индексе». Вопрос OP заключался в том, чтобы «назначить каждый элемент серии как новый столбец в DataFrame».
cs95
5

Вот один способ:

df.join(pd.DataFrame(s).T).fillna(method='ffill')

Чтобы понять, что здесь происходит ...

pd.DataFrame(s).Tсоздает однострочный DataFrame, sкоторый выглядит следующим образом:

   s1  s2
0   5   6

Затем joinобъединяет этот новый кадр с df:

   a  b  s1  s2
0  1  3   5   6
1  2  4 NaN NaN

Наконец, NaNзначения в индексе 1 заполняются предыдущими значениями в столбце с использованием аргумента fillnaforward-fill ( ffill):

   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

Чтобы избежать использования fillna, можно использовать pd.concatдля повторения строк DataFrame, созданного из s. В этом случае общее решение:

df.join(pd.concat([pd.DataFrame(s).T] * len(df), ignore_index=True))

Вот еще одно решение для решения проблемы индексации, поставленной в отредактированном вопросе:

df.join(pd.DataFrame(s.repeat(len(df)).values.reshape((len(df), -1), order='F'), 
        columns=s.index, 
        index=df.index))

sпреобразуется в DataFrame путем повторения значений и изменения формы (с указанием порядка Fortran), а также передачи соответствующих имен столбцов и индекса. Затем этот новый DataFrame присоединяется кdf .

Алекс Райли
источник
Хороший однострочник, предостережение в том, что любые NaN, уже находящиеся в df, также будут заполнены.
Натан Ллойд
@Nonth Спасибо и хорошее замечание. Я отредактировал, чтобы включить альтернативу, которая избегает заполнения NaNзначений.
Alex Riley
То, что произошло с исходным ответом EdChums, влияет на этот пересмотренный ответ. Если я построю df, скажем, index=[3, 5]новые столбцы будут содержать nan после вашей команды.
Натан Ллойд
@Nonth снова отредактировано! Теперь он должен соответствовать вашим новым требованиям.
Alex Riley
ваш ответ в 20 раз быстрее, но разница составляет ~ 100 мс с df на 1e5 строках. Мой цикл for ужасно медленный. Кстати, в вашем ответе это 2должно len(df)быть применимо в целом.
Натан Ллойд
0

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

df = pd.DataFrame({'a':[np.nan, 1, 2], 'b':[4, 5, 6]})

тогда вы можете установить значения s1 и s2 таким образом (используя shape () для возврата количества строк из df):

s = pd.DataFrame({'s1':[5]*df.shape[0], 's2':[6]*df.shape[0]})

тогда желаемый результат прост:

display (df.merge(s, left_index=True, right_index=True))

Или просто добавьте новые значения в свой фрейм данных df:

df = pd.DataFrame({'a':[nan, 1, 2], 'b':[4, 5, 6]})
df['s1']=5
df['s2']=6
display(df)

Оба возвращаются:

     a  b  s1  s2
0  NaN  4   5   6
1  1.0  5   5   6
2  2.0  6   5   6

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

s1=['a','b','c']

то вы можете прикрепить это таким же образом:

df['s1']=s1

возвращает:

     a  b s1
0  NaN  4  a
1  1.0  5  b
2  2.0  6  c
Джеймс
источник
0

Вы можете легко установить для столбца pandas.DataFrame константу. Эта константа может быть int, например, в вашем примере. Если указанного столбца нет в df, то pandas создаст новый столбец с указанным вами именем. Итак, после создания вашего фрейма данных (из вашего вопроса):

df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])

Вы можете просто запустить:

df['s1'], df['s2'] = 5, 6

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

Alex
источник
0

Если dfэто a, pandas.DataFrameто df['new_col']= Series list_object of length len(df)добавит объект or Series list_object в качестве столбца с именем 'new_col'.df['new_col']= scalar(например, 5 или 6 в вашем случае) также работает и эквивалентноdf['new_col']= [scalar]*len(df)

Таким образом, этой цели служит двухстрочный код:

df = pd.DataFrame({'a':[1, 2], 'b':[3, 4]})
s = pd.Series({'s1':5, 's2':6})
for x in s.index:    
    df[x] = s[x]

Output: 
   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6
Айшик Рой Чаудхури
источник