2014-10-12 1 views
8

Я заметил, что это issue on GitHub already. Есть ли у кого-нибудь код, который преобразует Pandas DataFrame в Orange Table?Преобразование Pandas DataFrame в Orange Table

Явно, у меня есть следующая таблица.

 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

оранжевый формат не выглядит, что трудно Ouput: http://docs.orange.biolab.si/reference/rst/Orange.data.formats.html также он поддерживает импорт файлов CSV и угадать тип данных , вы что-то пробовали? – EdChum

+0

Так что я мог понять, как данные сохраняются в *.а конкретно, есть ли функция или серия вызовов, которые вы можете сделать, что позволяет конвертировать Panda DataFrame в таблицу Orange? (Комментарий на стороне: смешно, как страница рассказывает о том, как данные хранятся во внешнем файле, но не говорит о том, как сохранять/загружать файлы. Я лично считаю, что Orange плохо документирована.) – hlin117

+0

Будет ли рабочий процесс, который экономит таблицу в Pandas в качестве файла, а затем импортировать файл в Orange? Или слишком много кудря? Я думаю, что полевые данные не могут быть переданы красиво. – BKay

ответ

17

Документация пакета Orange не распространяется на все детали. Table._init__(Domain, numpy.ndarray) работает только для int и float согласно lib_kernel.cpp.

Они действительно должны предоставить интерфейс уровня C для pandas.DataFrames или, по крайней мере, numpy.dtype("str").

Обновление: Добавление table2df, df2table производительность значительно улучшена за счет использования NumPy для Int и поплавком.

Сохраните этот кусок скрипта в своих коллекциях скриптов оранжевого питона, теперь у вас есть панды в оранжевой среде.

Использование: a_pandas_dataframe = table2df(a_orange_table), a_orange_table = df2table(a_pandas_dataframe)

Примечание: Этот скрипт работает только в Python 2.x, обратитесь к @DustinTang «s answer для Python 3.x совместимый сценарий.

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

Так что, похоже, вы предоставили очень тщательный ответ, спасибо! Работают ли эти функции для каждой таблицы Orange/Panda DataFrame? – hlin117

+0

Надеюсь, да, я тестировал свои собственные наборы данных, но может потребоваться больше тестов. – TurtleIzzy

+0

Это не сработало для меня в Python3 и Orange3. Однако, спасибо! –

1

Что-то вроде этого?

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

Столбцы в Orange получат общие имена (a1, a2 ...). Если вы хотите скопировать имена и типы из фрейма данных, постройте объект Orange.data.Domain (http://docs.orange.biolab.si/reference/rst/Orange.data.domain.html#Orange.data.Domain.init) из фрейма данных и передайте его в качестве первого аргумента выше.

Просмотреть конструкторы в http://docs.orange.biolab.si/reference/rst/Orange.data.table.html.

+0

Я получаю ошибку домена, когда я пытаюсь это сделать. «TypeError: недопустимые аргументы для конструктора (домен или примеры или оба ожидаемые)». Можете ли вы предоставить код для добавления домена? – hlin117

+1

Скажите, что у вас есть 'df = DataFrame ({" A ": [1, 2, 3, 4]," B ": [8, 7, 6, 5]})'. Создайте домен с доменом = Orange.data.Domain ([Orange.feature.Continuous (имя) для имени в df.columns]) ', а затем' table = Orange.data.Table (domain, df.as_matrix()) ' – JanezD

+0

О, если это не сработает: как выглядит кадр данных? Если 'df.as_matrix(). Dtype'' 'object', Orange не примет его. Вы должны преобразовать категориальные данные в индексы. – JanezD

2

Для того, чтобы преобразовать pandas DataFrame в Orange Table, вам необходимо создать домен, который задает типы столбцов.

Для непрерывных переменных вам нужно только указать имя переменной, но для дискретных переменных вам также необходимо предоставить список всех возможных значений.

Следующий код будет построен домен для DataFrame и преобразовать его в оранжевой таблицу:

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()]) 

Карта (улица, строка) шаг необходим, так Оранжевый знать, что данные содержат значение дискретных функций (а не индексы значений в списке значений).

+0

Это отлично работает! Я протестировал его, и, похоже, я мог бы сортировать таблицу по полу, поэтому я предполагаю, что большинство других функций таблицы будут работать. – hlin117

+0

Нет ли другого типа данных, если вы хотите описать функцию, являющуюся идентификатором? (Пример, идентификатор пользователя) – hlin117

2

Этот код изменен с @TurtleIzzy для 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)