2013-02-27 55 views
31

Tôi có một DataFrame gấu trúc, st chứa nhiều cột:Áp dụng chức năng để mỗi hàng của gấu trúc dataframe để tạo ra hai cột mới

<class 'pandas.core.frame.DataFrame'> 
DatetimeIndex: 53732 entries, 1993-01-07 12:23:58 to 2012-12-02 20:06:23 
Data columns: 
Date(dd-mm-yy)_Time(hh-mm-ss)  53732 non-null values 
Julian_Day       53732 non-null values 
AOT_1020       53716 non-null values 
AOT_870        53732 non-null values 
AOT_675        53188 non-null values 
AOT_500        51687 non-null values 
AOT_440        53727 non-null values 
AOT_380        51864 non-null values 
AOT_340        52852 non-null values 
Water(cm)       51687 non-null values 
%TripletVar_1020     53710 non-null values 
%TripletVar_870      53726 non-null values 
%TripletVar_675      53182 non-null values 
%TripletVar_500      51683 non-null values 
%TripletVar_440      53721 non-null values 
%TripletVar_380      51860 non-null values 
%TripletVar_340      52846 non-null values 
440-870Angstrom      53732 non-null values 
380-500Angstrom      52253 non-null values 
440-675Angstrom      53732 non-null values 
500-870Angstrom      53732 non-null values 
340-440Angstrom      53277 non-null values 
Last_Processing_Date(dd/mm/yyyy) 53732 non-null values 
Solar_Zenith_Angle     53732 non-null values 
dtypes: datetime64[ns](1), float64(22), object(1) 

Tôi muốn tạo ra hai cột mới cho dataframe này dựa trên việc áp dụng một chức năng để mỗi hàng của khung dữ liệu. Tôi không muốn phải gọi hàm này nhiều lần (ví dụ: bằng cách thực hiện hai cuộc gọi riêng biệt apply) vì nó khá tốn kém tính toán. Tôi đã cố gắng làm điều này theo hai cách, và không ai trong số họ làm việc:


Sử dụng apply:

Tôi đã viết một chức năng mà phải mất một Series và trả về một tuple trong những giá trị tôi muốn:

def calculate(s): 
    a = s['path'] + 2*s['row'] # Simple calc for example 
    b = s['path'] * 0.153 
    return (a, b) 

Đang cố gắng để áp dụng điều này để các DataFrame đưa ra một lỗi:

st.apply(calculate, axis=1) 
--------------------------------------------------------------------------- 
AssertionError       Traceback (most recent call last) 
<ipython-input-248-acb7a44054a7> in <module>() 
----> 1 st.apply(calculate, axis=1) 

C:\Python27\lib\site-packages\pandas\core\frame.pyc in apply(self, func, axis, broadcast, raw, args, **kwds) 
    4191      return self._apply_raw(f, axis) 
    4192     else: 
-> 4193      return self._apply_standard(f, axis) 
    4194    else: 
    4195     return self._apply_broadcast(f, axis) 

C:\Python27\lib\site-packages\pandas\core\frame.pyc in _apply_standard(self, func, axis, ignore_failures) 
    4274     index = None 
    4275 
-> 4276    result = self._constructor(data=results, index=index) 
    4277    result.rename(columns=dict(zip(range(len(res_index)), res_index)), 
    4278       inplace=True) 

C:\Python27\lib\site-packages\pandas\core\frame.pyc in __init__(self, data, index, columns, dtype, copy) 
    390    mgr = self._init_mgr(data, index, columns, dtype=dtype, copy=copy) 
    391   elif isinstance(data, dict): 
--> 392    mgr = self._init_dict(data, index, columns, dtype=dtype) 
    393   elif isinstance(data, ma.MaskedArray): 
    394    mask = ma.getmaskarray(data) 

C:\Python27\lib\site-packages\pandas\core\frame.pyc in _init_dict(self, data, index, columns, dtype) 
    521 
    522   return _arrays_to_mgr(arrays, data_names, index, columns, 
--> 523        dtype=dtype) 
    524 
    525  def _init_ndarray(self, values, index, columns, dtype=None, 

C:\Python27\lib\site-packages\pandas\core\frame.pyc in _arrays_to_mgr(arrays, arr_names, index, columns, dtype) 
    5411 
    5412  # consolidate for now 
-> 5413  mgr = BlockManager(blocks, axes) 
    5414  return mgr.consolidate() 
    5415 

C:\Python27\lib\site-packages\pandas\core\internals.pyc in __init__(self, blocks, axes, do_integrity_check) 
    802 
    803   if do_integrity_check: 
--> 804    self._verify_integrity() 
    805 
    806   self._consolidate_check() 

C:\Python27\lib\site-packages\pandas\core\internals.pyc in _verify_integrity(self) 
    892          "items") 
    893    if block.values.shape[1:] != mgr_shape[1:]: 
--> 894     raise AssertionError('Block shape incompatible with manager') 
    895   tot_items = sum(len(x.items) for x in self.blocks) 
    896   if len(self.items) != tot_items: 

AssertionError: Block shape incompatible with manager 

Sau đó, tôi sẽ chỉ định các giá trị được trả lại từ apply thành hai cột mới bằng cách sử dụng phương thức được hiển thị trong this question. Tuy nhiên, tôi thậm chí không thể đến được điểm này! Tất cả điều này hoạt động tốt nếu tôi chỉ trả lại một giá trị.


Sử dụng một vòng lặp:

đầu tiên tôi tạo ra hai cột mới của dataframe và đặt chúng vào None:

st['a'] = None 
st['b'] = None 

Sau đó looped qua tất cả các chỉ số và cố gắng sửa đổi những giá trị None mà tôi có trong đó, nhưng những sửa đổi tôi đã làm dường như không hoạt động. Tức là, không có lỗi nào được tạo ra, nhưng DataFrame dường như không bị sửa đổi.

for i in st.index: 
    # do calc here 
    st.ix[i]['a'] = a 
    st.ix[i]['b'] = b 

Tôi nghĩ rằng cả hai phương pháp sẽ làm việc, nhưng không ai trong số họ đã làm. Vì vậy, tôi đang làm gì sai ở đây? Và cách tốt nhất, 'pythonic' và 'pandaonic' tốt nhất để làm điều này là gì?

Trả lời

24

Để làm cho phương pháp tiếp cận đầu tiên hoạt động, hãy thử trả về một Series thay vì một bộ (áp dụng là ném một ngoại lệ vì nó không biết cách dán các hàng lại với nhau vì số cột không khớp với khung gốc).

def calculate(s): 
    a = s['path'] + 2*s['row'] # Simple calc for example 
    b = s['path'] * 0.153 
    return pd.Series(dict(col1=a, col2=b)) 

Cách tiếp cận thứ hai nên làm việc nếu bạn thay thế:

st.ix[i]['a'] = a 

với:

st.ix[i, 'a'] = a 
+0

Giải pháp cho phương pháp tiếp cận thứ hai hoạt động - cảm ơn :-). Tuy nhiên, tôi không thể có được cách tiếp cận đầu tiên để làm việc. Trả về một chuỗi các công trình, và tôi nhận được một 'mini-df' trả về, nhưng tôi dường như không thể lấy lại các giá trị từ hàm 'apply' vào khung dữ liệu ban đầu. Sử dụng 'st ['a'], st ['b'] = st.apply (tính, trục = 1)' không hoạt động, và không bao bọc phần bên phải trong 'zip (*)'. Bất kỳ ý tưởng về những gì tôi đang làm sai ở đây? – robintw

+1

Bạn có thể nối các cột 'mini' df vào DataFrame gốc với 'pd.concat ([df, new_df], axis = 1)'. Bạn cũng có thể muốn xem xét các hoạt động dựa trên cột, thay vì dựa trên hàng, ví dụ, tính toán và thêm cột 'a' với 'df ['a'] = df ['path'] + 2 * df ['row'] ' – Garrett

4

này đã được giải quyết ở đây: Apply pandas function to column to create multiple new columns?

Áp dụng cho câu hỏi của bạn này nên làm việc :

def calculate(s): 
    a = s['path'] + 2*s['row'] # Simple calc for example 
    b = s['path'] * 0.153 
    return pd.Series({'col1': a, 'col2': b}) 

df = df.merge(df.apply(calculate, axis=1), left_index=True, right_index=True) 
+0

Điều này chỉ làm việc cho tôi nếu tôi sử dụng: trả về pd.Series ({'col1': a, 'col2': b}), là cú pháp = cụ thể cho một số phiên bản của python? – danio

11

tôi luôn luôn sử dụng lambdas và được xây dựng trong map() chức năng để tạo ra các hàng mới bằng cách kết hợp các hàng khác:

st['a'] = map(lambda path, row: path + 2 * row, st['path'], st['row']) 

Nó có thể là một chút phức tạp hơn cần thiết để thực hiện kết hợp tuyến tính của các cột số. Mặt khác, tôi cảm thấy rất tốt khi áp dụng như một quy ước vì nó có thể được sử dụng với các kết hợp hàng phức tạp hơn (ví dụ: làm việc với chuỗi) hoặc điền dữ liệu bị thiếu trong cột bằng cách sử dụng các hàm của các cột khác.

Ví dụ: giả sử bạn có bảng có giới tính và tiêu đề cột và một số tiêu đề bị thiếu. Bạn có thể điền chúng với chức năng như sau:

title_dict = {'male': 'mr.', 'female': 'ms.'} 
table['title'] = map(lambda title, 
    gender: title if title != None else title_dict[gender], 
    table['title'], table['gender']) 
+1

Trong Python 3, bạn sẽ cần sử dụng 'tuple (map (…))' thay vì chỉ 'map (…)'. – Rufflewind

0

Tuy nhiên, một giải pháp dựa trên Assigning New Columns in Method Chains:

st.assign(a = st['path'] + 2*st['row'], b = st['path'] * 0.153) 

Hãy nhận biết assignluôn trả về một bản sao của dữ liệu, bỏ rơi DataFrame gốc hoang sơ.

Các vấn đề liên quan