2017-01-10 26 views
7

Tôi có khung dữ liệu sau:Làm thế nào để trao đổi một nhóm các tiêu đề cột với các giá trị của họ trong Pandas

a1 | a2 | a3 | a4 
--------------------- 
Bob | Cat | Dov | Edd 
Cat | Dov | Bob | Edd 
Edd | Cat | Dov | Bob 

và tôi muốn chuyển nó sang

Bob | Cat | Dov | Edd 
--------------------- 
a1 | a2 | a3 | a4 
a3 | a1 | a2 | a4 
a4 | a2 | a3 | a1 

Lưu ý rằng số lượng các cột bằng số lượng giá trị duy nhất và số lượng và thứ tự của các hàng được giữ nguyên

Trả lời

9

1) phương pháp bắt buộc:

Một thực hiện nhanh hơn sẽ là để sắp xếp các giá trị của dataframe và sắp xếp các cột phù hợp dựa trên nó sẽ được lấy chỉ số sau np.argsort.

pd.DataFrame(df.columns[np.argsort(df.values)], df.index, np.unique(df.values)) 

enter image description here

Áp dụng np.argsort cho chúng ta dữ liệu chúng tôi đang tìm kiếm:

df.columns[np.argsort(df.values)] 
Out[156]: 
Index([['a1', 'a2', 'a3', 'a4'], ['a3', 'a1', 'a2', 'a4'], 
     ['a4', 'a2', 'a3', 'a1']], 
     dtype='object') 

2) cách tiếp cận tổng quát chậm:

Cách tiếp cận tổng quát hơn trong khi với chi phí của một số tốc độ/hiệu quả sẽ là sử dụng apply sau khi tạo ánh xạ của các chuỗi/giá trị có trong khung dữ liệu có tên cột tương ứng của chúng.

Sử dụng trình tạo khung dữ liệu sau này sau khi chuyển đổi chuỗi đã thu được thành biểu diễn list của chúng.

pd.DataFrame(df.apply(lambda s: dict(zip(pd.Series(s), pd.Series(s).index)), 1).tolist()) 

3) cách tiếp cận nhanh hơn tổng quát:

Sau khi có một danh sách các từ điển từ df.to_dict + orient='records', chúng ta cần phải trao đổi nó quan trọng và giá trị tương ứng của cặp trong khi iterating qua chúng trong một vòng lặp.

pd.DataFrame([{val:key for key, val in d.items()} for d in df.to_dict('r')]) 

trường hợp thử nghiệm mẫu:

df = df.assign(a5=['Foo', 'Bar', 'Baz']) 

Cả hai phương pháp sản xuất:

enter image description here


@piRSquared EDIT

giải pháp tổng quát

def nic(df): 
    v = df.values 
    n, m = v.shape 
    u, inv = np.unique(v, return_inverse=1) 
    i = df.index.values 
    c = df.columns.values 
    r = np.empty((n, len(u)), dtype=c.dtype) 
    r[i.repeat(m), inv] = np.tile(c, n) 
    return pd.DataFrame(r, i, u) 

Tôi muốn gửi lời cảm ơn user @piRSquared cho đến với một NumPy thực sự nhanh chóng và tổng quát dựa soln thay thế.

+1

lưu ý rằng điều này chỉ hoạt động trong những trường hợp đặc biệt trong đó mọi thứ được đại diện gọn gàng. Đó là một câu trả lời tuyệt vời, tôi chỉ chỉ nó ra – piRSquared

+1

Cảm ơn. Tôi đoán OP đã đề cập đến trường hợp này ở cuối bài đăng của họ. Nếu không, nếu không phải tất cả các cột đều được biểu diễn bằng nhau, thì tôi đoán điều này sẽ thất bại. –

+0

Điều đó có ý nghĩa – piRSquared

5

Bạn có thể định hình lại giá trị đó bằng cách hoán đổi giá trị và chỉ mục:

df_swap = (df.stack()      # reshape the data frame to long format 
      .reset_index(level = 1)  # set the index(column headers) as a new column 
      .set_index(0, append=True) # set the values as index 
      .unstack(level=1))   # reshape the data frame to wide format 

df_swap.columns = df_swap.columns.get_level_values(1) # drop level 0 in the column index 
df_swap 

enter image description here

+1

Tôi tin 'to_frame' là không bắt buộc, là 'reset_index' trả về một dataframe. – IanS

+0

Cảm ơn bạn đã phản hồi nhanh chóng và giải thích :) – edmondawad

1

numpy + pandas

v = df.values 
n, m = v.shape 
i = df.index.values 
c = df.columns.values 

# create series with values that were column values 
# create multi index with first level from existing index 
# and second level from flattened existing values 
# then unstack 
pd.Series(
    np.tile(c, n), 
    [i.repeat(m), v.ravel()] 
).unstack() 

    Bob Cat Dov Edd 
0 a1 a2 a3 a4 
1 a3 a1 a2 a4 
2 a4 a2 a3 a1 
Các vấn đề liên quan