Как объединить серию и DataFrame
Если вы пришли сюда в поисках информации о том, как объединить 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
Ответы
Ответ 1
Вы можете построить блок данных из серии и затем объединиться с файловой рамкой.
Поэтому вы указываете данные как значения, но умножаете их на длину, устанавливаете столбцы в индекс и устанавливаете параметры для 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)
Это предполагает, что индексы соответствуют длине.
Ответ 2
В настоящее время вы можете просто преобразовать Series в DataFrame с помощью to_frame(). Итак (при присоединении по индексу):
df.merge(s.to_frame(), left_index=True, right_index=True)
Начиная с v0.24.0, вы можете объединять DataFrame и Series, пока Series назван.
df.merge(s.rename('new'), left_index=True, right_index=True)
Ответ 3
Здесь один из способов:
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 заполняются предыдущими значениями в столбце с использованием fillna
с fillna
forward-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
.
Ответ 4
Текущий с v0.23.4
- альтернативы для merge
Объединение DataFrame
и Series
Настроить
df
a b
s1 NaN 4
s2 2.0 5
s3 3.0 6
s
s1 5
s2 6
dtype: int64
pd.concat
Если вы хотите объединить DataFrame или Series с индексом, вы можете использовать pd.concat
, который принимает ряд:
pd.concat([df, s], axis=1, sort=False, join='inner')
a b 0
s1 NaN 4 5
s2 2.0 5 6
Который такой же как (но быстрее чем)
df.merge(s.to_frame(), left_index=True, right_index=True)
a b 0
s1 NaN 4 5
s2 2.0 5 6
DataFrame.assign
Используйте assign
, добавив шаг loc
для индексации с пересечением индекса.
df2.assign(new=s).loc[(df.index & s.index).unique()]
Это также обрабатывает дубликаты в индексе (что concat
не может).
df2 = df.copy()
df2.index = ['s1', 's2', 's1']
df2
a b
s1 NaN 4
s2 2.0 5
s1 3.0 6
df2.assign(new=s).loc[(df.index & s.index).unique()]
# Equivalent to
# df.merge(s.to_frame(), left_index=True, right_index=True)
a b new
s1 NaN 4 5
s1 3.0 6 5
s2 2.0 5 6
Если индекс уникален, решение немного упрощается, отбросьте вызов unique
:
df2.assign(new=s).loc[df.index & s.index]
Отвечая на вопрос ОП - df.assign
, снова
df.assign(**s)
a b s1 s2
0 1 3 5 6
1 2 4 5 6
а также,
a b s1 s2
3 NaN 4 5 6
5 2.0 5 5 6
6 3.0 6 5 6
(Это работает на обоих примерах.)
Ответ 5
Если бы я мог предложить настроить ваши данные как это (автоиндексирование):
df = pd.DataFrame({'a':[np.nan, 1, 2], 'b':[4, 5, 6]})
тогда вы можете настроить свои значения s1 и s2 таким образом (используя форму(), чтобы вернуть количество строк из df):
s = pd.DataFrame({'s1':[5]*df.shape[0], 's2':[6]*df.shape[0]})
то нужный результат легко:
display (df.merge(s, left_index=True, right_index=True))
В качестве альтернативы просто добавьте новые значения в ваш dataframe 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
Ответ 6
Вы можете легко установить столбец pandas.DataFrame в константу. Эта константа может быть int, как в вашем примере. Если указанный вами столбец отсутствует в df, тогда pandas создаст новый столбец с указанным вами именем. Итак, после того, как ваш dataframe построен, (из вашего вопроса):
df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])
Вы можете просто запустить:
df['s1'], df['s2'] = 5, 6
Вы можете написать цикл или понимание, чтобы он делал это для всех элементов в списке кортежей или ключей и значений в словаре в зависимости от того, как хранятся ваши реальные данные.