2014-10-12 46 views
8

Tôi nhận thấy rằng đây là một issue on GitHub already. Có ai có bất kỳ mã nào chuyển đổi một khung dữ liệu Pandas sang một bảng màu cam không?Chuyển đổi Pandas DataFrame đến Orange Bảng

Rõ ràng, tôi có bảng sau đây.

 user hotel star_rating user home_continent gender 
0   1  39   4.0  1    2 female 
1   1  44   3.0  1    2 female 
2   2  63   4.5  2    3 female 
3   2  2   2.0  2    3 female 
4   3  26   4.0  3    1 male 
5   3  37   5.0  3    1 male 
6   3  63   4.5  3    1 male 
+0

Định dạng cam không giống là khó khăn để ouput: http://docs.orange.biolab.si/reference/rst/Orange.data.formats.html cũng nó hỗ trợ nhập khẩu file csv và đoán các kiểu dữ liệu bạn đã thử cái gì chưa? – EdChum

+0

Vì vậy, tôi có thể hiểu cách dữ liệu được lưu thành *.tệp tab, nhưng cụ thể, là có một chức năng hoặc một loạt các cuộc gọi bạn có thể thực hiện cho phép bạn chuyển đổi một DataFrame gấu trúc sang một bảng màu cam? (Bình luận phụ: Thật buồn cười khi trang nói về cách dữ liệu được lưu trữ trong một tệp bên ngoài, nhưng không nói về cách lưu/tải từ các tệp. Cá nhân tôi nghĩ rằng Orange không được ghi lại đầy đủ.) – hlin117

+0

Quy trình làm việc có thể lưu bảng trong Pandas như một tập tin và sau đó nhập khẩu các tập tin trong Orange làm việc? Hoặc quá nhiều kludge? Tôi đoán các kiểu dữ liệu của trường có thể không được truyền đi một cách độc đáo. – BKay

Trả lời

17

Tài liệu về gói Orange không bao gồm tất cả các chi tiết. Table._init__(Domain, numpy.ndarray) chỉ hoạt động cho intfloat theo lib_kernel.cpp.

Họ thực sự cần cung cấp giao diện cấp C cho pandas.DataFrames hoặc ít nhất numpy.dtype("str") hỗ trợ.

Cập nhật: Thêm table2df, df2table hiệu suất cải thiện đáng kể bằng cách sử dụng NumPy cho int và float.

Giữ mảnh này của kịch bản trong bộ sưu tập kịch bản cam python của bạn, bây giờ bạn được trang bị gấu trúc trong môi trường cam của bạn.

Cách sử dụng: a_pandas_dataframe = table2df(a_orange_table), a_orange_table = df2table(a_pandas_dataframe)

Note: Kịch bản này chỉ hoạt động bằng Python 2.x, hãy tham khảo @DustinTang 's answer cho Python 3.x kịch bản tương thích.

import pandas as pd 
import numpy as np 
import Orange 

#### For those who are familiar with pandas 
#### Correspondence: 
#### value <-> Orange.data.Value 
####  NaN <-> ["?", "~", "."] # Don't know, Don't care, Other 
#### dtype <-> Orange.feature.Descriptor 
####  category, int <-> Orange.feature.Discrete # category: > pandas 0.15 
####  int, float <-> Orange.feature.Continuous # Continuous = core.FloatVariable 
####             # refer to feature/__init__.py 
####  str <-> Orange.feature.String 
####  object <-> Orange.feature.Python 
#### DataFrame.dtypes <-> Orange.data.Domain 
#### DataFrame.DataFrame <-> Orange.data.Table = Orange.orange.ExampleTable 
####        # You will need this if you are reading sources 

def series2descriptor(d, discrete=False): 
    if d.dtype is np.dtype("float"): 
     return Orange.feature.Continuous(str(d.name)) 
    elif d.dtype is np.dtype("int"): 
     return Orange.feature.Continuous(str(d.name), number_of_decimals=0) 
    else: 
     t = d.unique() 
     if discrete or len(t) < len(d)/2: 
      t.sort() 
      return Orange.feature.Discrete(str(d.name), values=list(t.astype("str"))) 
     else: 
      return Orange.feature.String(str(d.name)) 


def df2domain(df): 
    featurelist = [series2descriptor(df.icol(col)) for col in xrange(len(df.columns))] 
    return Orange.data.Domain(featurelist) 


def df2table(df): 
    # It seems they are using native python object/lists internally for Orange.data types (?) 
    # And I didn't find a constructor suitable for pandas.DataFrame since it may carry 
    # multiple dtypes 
    # --> the best approximate is Orange.data.Table.__init__(domain, numpy.ndarray), 
    # --> but the dtype of numpy array can only be "int" and "float" 
    # --> * refer to src/orange/lib_kernel.cpp 3059: 
    # --> * if (((*vi)->varType != TValue::INTVAR) && ((*vi)->varType != TValue::FLOATVAR)) 
    # --> Documents never mentioned >_< 
    # So we use numpy constructor for those int/float columns, python list constructor for other 

    tdomain = df2domain(df) 
    ttables = [series2table(df.icol(i), tdomain[i]) for i in xrange(len(df.columns))] 
    return Orange.data.Table(ttables) 

    # For performance concerns, here are my results 
    # dtndarray = np.random.rand(100000, 100) 
    # dtlist = list(dtndarray) 
    # tdomain = Orange.data.Domain([Orange.feature.Continuous("var" + str(i)) for i in xrange(100)]) 
    # tinsts = [Orange.data.Instance(tdomain, list(dtlist[i]))for i in xrange(len(dtlist))] 
    # t = Orange.data.Table(tdomain, tinsts) 
    # 
    # timeit list(dtndarray) # 45.6ms 
    # timeit [Orange.data.Instance(tdomain, list(dtlist[i])) for i in xrange(len(dtlist))] # 3.28s 
    # timeit Orange.data.Table(tdomain, tinsts) # 280ms 

    # timeit Orange.data.Table(tdomain, dtndarray) # 380ms 
    # 
    # As illustrated above, utilizing constructor with ndarray can greatly improve performance 
    # So one may conceive better converter based on these results 


def series2table(series, variable): 
    if series.dtype is np.dtype("int") or series.dtype is np.dtype("float"): 
     # Use numpy 
     # Table._init__(Domain, numpy.ndarray) 
     return Orange.data.Table(Orange.data.Domain(variable), series.values[:, np.newaxis]) 
    else: 
     # Build instance list 
     # Table.__init__(Domain, list_of_instances) 
     tdomain = Orange.data.Domain(variable) 
     tinsts = [Orange.data.Instance(tdomain, [i]) for i in series] 
     return Orange.data.Table(tdomain, tinsts) 
     # 5x performance 


def column2df(col): 
    if type(col.domain[0]) is Orange.feature.Continuous: 
     return (col.domain[0].name, pd.Series(col.to_numpy()[0].flatten())) 
    else: 
     tmp = pd.Series(np.array(list(col)).flatten()) # type(tmp) -> np.array(dtype=list (Orange.data.Value)) 
     tmp = tmp.apply(lambda x: str(x[0])) 
     return (col.domain[0].name, tmp) 

def table2df(tab): 
    # Orange.data.Table().to_numpy() cannot handle strings 
    # So we must build the array column by column, 
    # When it comes to strings, python list is used 
    series = [column2df(tab.select(i)) for i in xrange(len(tab.domain))] 
    series_name = [i[0] for i in series] # To keep the order of variables unchanged 
    series_data = dict(series) 
    print series_data 
    return pd.DataFrame(series_data, columns=series_name) 
+0

Vì vậy, có vẻ như bạn đã cung cấp phản hồi rất kỹ lưỡng, cảm ơn! Các chức năng này có hoạt động với mọi bảng màu da cam/DataFrame Panda không? – hlin117

+0

Hy vọng là có, tôi đã thử nghiệm trên bộ dữ liệu của riêng mình nhưng có thể cần thêm nhiều thử nghiệm. – TurtleIzzy

+0

Điều này đã không làm việc cho tôi trong Python3 và Orange3. Tuy nhiên, cảm ơn! –

1

Cái gì như thế này?

table = Orange.data.Table(df.as_matrix()) 

Các cột trong Orange sẽ có tên chung (a1, a2 ...). Nếu bạn muốn sao chép tên và các loại từ khung dữ liệu, hãy xây dựng đối tượng Orange.data.Domain (http://docs.orange.biolab.si/reference/rst/Orange.data.domain.html#Orange.data.Domain.init) từ khung dữ liệu và chuyển nó làm đối số đầu tiên ở trên.

Xem các nhà thầu trong http://docs.orange.biolab.si/reference/rst/Orange.data.table.html.

+0

Tôi gặp lỗi miền khi thử. "TypeError: đối số không hợp lệ cho hàm tạo (tên miền hoặc ví dụ hoặc cả hai được mong đợi)". Bạn có thể cung cấp một số mã để thêm vào một miền không? – hlin117

+1

Giả sử bạn có 'df = DataFrame ({" A ": [1, 2, 3, 4]," B ": [8, 7, 6, 5]})'. Tạo miền với 'domain = Orange.data.Domain ([Orange.feature.Continuous (name) cho tên trong df.columns])' và sau đó 'table = Orange.data.Table (domain, df.as_matrix()) ' – JanezD

+0

Ồ, nếu nó không hoạt động: khung dữ liệu của bạn trông như thế nào? Nếu 'df.as_matrix(). Dtype' là' đối tượng', Orange sẽ không chấp nhận nó. Bạn phải chuyển đổi dữ liệu phân loại thành chỉ mục. – JanezD

2

Để chuyển đổi gấu trúc DataFrame đến Orange Bảng bạn cần phải xây dựng một miền, trong đó quy định cụ thể các loại cột.

Đối với các biến liên tục, bạn chỉ cần cung cấp tên của biến, nhưng đối với các biến rời rạc, bạn cũng cần phải cung cấp một danh sách của tất cả các giá trị có thể.

Đoạn mã dưới đây sẽ xây dựng một miền với DataFrame của bạn và chuyển nó sang một Bảng Orange:

import numpy as np 
from Orange.feature import Discrete, Continuous 
from Orange.data import Domain, Table 
domain = Domain([ 
    Discrete('user', values=[str(v) for v in np.unique(df.user)]), 
    Discrete('hotel', values=[str(v) for v in np.unique(df.hotel)]), 
    Continuous('star_rating'), 
    Discrete('user', values=[str(v) for v in np.unique(df.user)]), 
    Discrete('home_continent', values=[str(v) for v in np.unique(df.home_continent)]), 
    Discrete('gender', values=['male', 'female'])], False) 
table = Table(domain, [map(str, row) for row in df.as_matrix()]) 

Bản đồ (str, hàng) bước cần thiết để Orange biết rằng các dữ liệu chứa các giá trị của tính năng rời rạc (và không phải là chỉ số của các giá trị trong danh sách giá trị).

+0

Công trình này tuyệt vời! Tôi đã thử nghiệm nó ra, và có vẻ như tôi có thể sắp xếp các bảng theo giới tính, vì vậy tôi sẽ giả định hầu hết các chức năng bảng khác sẽ làm việc. – hlin117

+0

Không có loại dữ liệu nào khác nếu bạn muốn mô tả một đối tượng địa lý là một ID? (Ví dụ, ID người dùng) – hlin117

2

Mã này được sửa đổi từ @TurtleIzzy for Python3.

import numpy as np 
from Orange.data import Table, Domain, ContinuousVariable, DiscreteVariable 


def series2descriptor(d): 
    if d.dtype is np.dtype("float") or d.dtype is np.dtype("int"): 
     return ContinuousVariable(str(d.name)) 
    else: 
     t = d.unique() 
     t.sort() 
     return DiscreteVariable(str(d.name), list(t.astype("str"))) 

def df2domain(df): 
    featurelist = [series2descriptor(df.iloc[:,col]) for col in range(len(df.columns))] 
    return Domain(featurelist) 

def df2table(df): 
    tdomain = df2domain(df) 
    ttables = [series2table(df.iloc[:,i], tdomain[i]) for i in range(len(df.columns))] 
    ttables = np.array(ttables).reshape((len(df.columns),-1)).transpose() 
    return Table(tdomain , ttables) 

def series2table(series, variable): 
    if series.dtype is np.dtype("int") or series.dtype is np.dtype("float"): 
     series = series.values[:, np.newaxis] 
     return Table(series) 
    else: 
     series = series.astype('category').cat.codes.reshape((-1,1)) 
     return Table(series) 
Các vấn đề liên quan