Cách hợp nhất một Chuỗi và DataFrame


82

Nếu bạn đến đây để tìm kiếm thông tin về cách hợp nhất a DataFrameSeriestrên chỉ mục , vui lòng xem câu trả lời này .

Mục đích ban đầu của OP là hỏi cách gán các phần tử chuỗi dưới dạng cột cho DataFrame khác . Nếu bạn muốn biết câu trả lời cho điều này, hãy xem câu trả lời được chấp nhận bởi EdChum.


Tốt nhất tôi có thể nghĩ ra là

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

Ai có thể đề xuất cú pháp tốt hơn / phương pháp nhanh hơn?

Cố gắng của tôi:

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

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

CHỈNH SỬA Hai câu trả lời đầu tiên được đăng làm nổi bật một vấn đề với câu hỏi của tôi, vì vậy vui lòng sử dụng phần sau để xây dựng df:

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

với kết quả cuối cùng

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

Câu trả lời:


25

Bạn có thể tạo khung dữ liệu từ chuỗi và sau đó hợp nhất với khung dữ liệu. Vì vậy, bạn chỉ định dữ liệu dưới dạng các giá trị nhưng nhân chúng với độ dài, đặt các cột thành chỉ mục và đặt các tham số cho left_index và right_index thành 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

CHỈNH SỬA cho trường hợp bạn muốn chỉ mục của df đã xây dựng của bạn từ chuỗi sử dụng chỉ mục của df thì bạn có thể làm như sau:

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

Điều này giả định rằng các chỉ số phù hợp với độ dài.


163

Cập nhật
Từ v0.24.0 trở đi, bạn có thể hợp nhất trên DataFrame và Series miễn là Series được đặt tên.

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)

Ngày nay, bạn có thể chỉ cần chuyển đổi Series thành DataFrame với to_frame () . Vì vậy (nếu tham gia trên chỉ mục):

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

5
Sử dụng các định nghĩa của câu hỏi về dfs, câu trả lời này trả về cho tôi một khung dữ liệu trống, không phải kết quả được yêu cầu trong câu hỏi. Chúng tôi không muốn khớp về chỉ mục; chúng tôi muốn phát các sgiá trị cho tất cả các hàng của df.
CPBL

2
Điều này đang giải quyết một vấn đề khác: "được cung cấp DataFrame và Series, làm thế nào chúng có thể được hợp nhất trên chỉ mục". Câu hỏi của OP là "gán mỗi phần tử của Chuỗi làm cột mới trong DataFrame".
cs95

5

Đây là một cách:

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

Để phá vỡ những gì xảy ra ở đây ...

pd.DataFrame(s).Ttạo DataFrame một hàng từ sđó trông giống như sau:

   s1  s2
0   5   6

Tiếp theo, joinnối khung mới này với df:

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

Cuối cùng, các NaNgiá trị tại chỉ mục 1 được điền bằng các giá trị trước đó trong cột bằng cách sử dụng fillnađối số forward-fill ( ffill):

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

Để tránh sử dụng fillna, có thể sử dụng pd.concatđể lặp lại các hàng của DataFrame được tạo từ đó s. Trong trường hợp này, giải pháp chung là:

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

Đây là một giải pháp khác để giải quyết thách thức lập chỉ mục được đặt ra trong câu hỏi đã chỉnh sửa:

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

sđược chuyển đổi thành DataFrame bằng cách lặp lại các giá trị và định hình lại (chỉ định thứ tự 'Fortran'), đồng thời chuyển các tên và chỉ mục cột thích hợp. DataFrame mới này sau đó được kết hợp với df.


Một điều tuyệt vời, một lưu ý là bất kỳ NaN nào đã có trong df cũng sẽ bị lấp đầy.
Nathan Lloyd

@Nonth Cảm ơn và điểm tốt. Tôi đã chỉnh sửa để đưa vào một giải pháp thay thế tránh điền vào NaNcác giá trị.
Alex Riley

Điều gì đã xảy ra với câu trả lời gốc của EdChums ảnh hưởng đến câu trả lời đã sửa đổi này. Nếu tôi xây dựng df với, chẳng hạn index=[3, 5], các cột mới chứa nan sau lệnh của bạn.
Nathan Lloyd

@Nonth đã được chỉnh sửa lại! Bây giờ nó sẽ đáp ứng các yêu cầu mới của bạn.
Alex Riley

câu trả lời của bạn nhanh hơn 20 lần, nhưng vẫn chênh lệch ~ 100ms với df ở 1e5 hàng. Vòng lặp for của tôi chậm kinh khủng. BTW trong câu trả lời của bạn 2phải len(df)được áp dụng chung.
Nathan Lloyd

0

Nếu tôi có thể đề xuất thiết lập khung dữ liệu của bạn như thế này (tự động lập chỉ mục):

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

thì bạn có thể thiết lập các giá trị s1 và s2 của mình do đó (sử dụng shape () để trả về số hàng từ df):

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

thì kết quả bạn muốn thật dễ dàng:

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

Ngoài ra, chỉ cần thêm các giá trị mới vào df khung dữ liệu của bạn:

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

Cả hai đều trở lại:

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

Nếu bạn có một danh sách dữ liệu khác (thay vì chỉ một giá trị duy nhất để áp dụng) và bạn biết nó nằm trong cùng một chuỗi với df, ví dụ:

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

thì bạn có thể đính kèm cái này theo cách tương tự:

df['s1']=s1

trả lại:

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

0

Bạn có thể dễ dàng đặt cột pandas.DataFrame thành một hằng số. Hằng số này có thể là một số nguyên chẳng hạn như trong ví dụ của bạn. Nếu cột bạn chỉ định không có trong df, thì gấu trúc sẽ tạo một cột mới với tên bạn chỉ định. Vì vậy, sau khi khung dữ liệu của bạn được tạo, (từ câu hỏi của bạn):

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

Bạn chỉ có thể chạy:

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

Bạn có thể viết một vòng lặp hoặc hiểu để thực hiện điều này cho tất cả các phần tử trong danh sách các bộ giá trị hoặc các khóa và giá trị trong từ điển tùy thuộc vào cách bạn lưu trữ dữ liệu thực của mình.


0

Nếu dflà một pandas.DataFramethì df['new_col']= Series list_object of length len(df)sẽ thêm hoặc Series list_object làm cột có tên 'new_col'.df['new_col']= scalar(chẳng hạn như 5 hoặc 6 trong trường hợp của bạn) cũng hoạt động và tương đương vớidf['new_col']= [scalar]*len(df)

Vì vậy, mã hai dòng phục vụ mục đích:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.