Як об’єднати серію та 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

EDIT Перші дві опубліковані відповіді висвітлили проблему з моїм запитанням, тому, будь ласка, використовуйте наступне для побудови 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

EDIT для ситуації, коли ви хочете, щоб індекс вашого побудованого df із серії використовував індекс df, тоді ви можете зробити наступне:

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

Це передбачає, що показники відповідають довжині.


168

Оновлення
Починаючи з v0.24.0 і далі, ви можете об’єднувати DataFrame і Series, доки названа 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 заповнюються попередніми значеннями в стовпці за fillnaдопомогою ffillаргументу forward-fill ( ):

   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, також заповниться.
Nathan Lloyd,

@Nonth Дякую та хороший момент. Я редагував, щоб включити альтернативу, яка уникає заповнення NaNзначень.
Алекс Райлі

Те, що сталося з оригінальною відповіддю EdChums, впливає на цю переглянуту відповідь. Якщо я побудую df, скажімо, index=[3, 5]нові стовпці містять nn після вашої команди.
Натан Ллойд,

@Nonth Відредаговано знову! Тепер він повинен відповідати вашим новим вимогам.
Алекс Райлі

ваша відповідь у 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

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


0

Якщо dfє, pandas.DataFrameтоді df['new_col']= Series list_object of length len(df)додасть або Серія 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.