2013-12-16 3 views
2

У меня проблемы с производительностью и «уродливым кодом», и, возможно, некоторые из вас могут помочь. Мне нужно экспортировать данные из netCDF-файлы в * .csv. Для этого я написал код python. Давайте 3-тусклый NetCDF-файл:netCDF to * .csv without Loops (!)

def to3dim_csv(): 
    var = ncf.variables['H2O'] #e.g. data for 'H2O' values 
    one,two,three = var.shape #variable dimension shape e.g. (551,42,94) 
    dim1,dim2,dim3 = var.dimensions #dimensions e.g. (time,lat,lon) 

    if crit is not None: 
    bool1 = foo(dim1,crit,ncf) #boolean table: ("value important?",TRUE,FALSE) 
    bool2 = foo(dim2,crit,ncf) 
    bool3 = foo(dim3,crit,ncf) 

    writer.writerow([dim1,dim2,dim3,varn]) 
    for i in range(one): 
    for k in range(two): 
     for l in range(three): 
     if bool1[i] and bool2[k] and bool3[l]: 
      writer.writerow([ 
         ncf.variables[dim1][i], 
         ncf.variables[dim2][k], 
         ncf.variables[dim3][l], 
         var[i,k,l], 
         ]) 
    ofile.close() 

    # Sample csv output is like: 
    # time,lat,lon,H2O 
    # 1,90,10,100 
    # 1,90,11,90 
    # 1,91,10,101 

Я хочу, чтобы удалить for val in range(d): блоки. Возможно, с помощью функции recursiv, как:

var = ncf.variables['H2O'] 
dims = [d for d in var.dimensions] 
shapes = [var.variables[d].shape for d in dims] 
bools = [bool_table(d,crit,ncf) for d in dims] 
dims.append('H2O') 
writer.writerow(dims) 
magic_function(data) 

def magic_function(data): 

    [enter code] 

    writer.writerow(data) 
    magic_function(left_data) 

Update: Для тех, кто заинтересован. Это работает мгновенно ...

def data_to_table(dataset, var): 
    assert isinstance(dataset,xr.Dataset), 'Dataset must be xarray.Dataset' 
    obj = getattr(dataset, var) 
    table = np.zeros((obj.data.size, obj.data.ndim+1), dtype=np.object_) 
    table[:,0] = obj.data.flat 
    for i,d in enumerate(obj.dims): 
     repeat = np.prod(obj.data.shape[i+1:]) 
     tile = np.prod(obj.data.shape[:i]) 
     dim = getattr(dataset, d) 
     dimdata = dim.data 
     dimdata = np.repeat(dimdata, repeat) 
     dimdata = np.tile(dimdata, tile) 
     table[:,i+1] = dimdata.flat 
    return table 

def export_to_csv(dataset, var, filename, size=None): 
    obj = getattr(dataset, var) 
    header = [var] + [x for x in obj.dims] 
    tabular = data_to_table(dataset, var) 
    size = slice(None,size,None) if size else slice(None,None,None) 
    with open(filename, 'w') as f: 
     writer = csv.writer(f,dialect=csv.excel) 
     writer.writerow(header) 
     writer.writerows(tabular[size]) 
+0

1. Это выглядит уродливо, если мне нужно повторить код для каждого n-мерного. 2. Для прохождения всех данных требуется много времени. Возможно, у кого-то есть идея использовать 'ncdump' или аналогичную функцию для увеличения скорости - [комментарий удален, я ответил на] – ucyo

+0

, используя рекурсивную функцию здесь не принесет выигрыша от производительности – goncalopp

+0

numpy булевское индексирование массивов должно ускорить это ? – M4rtini

ответ

2

Нечто подобное. Получите индексы bol1 \ 2 \ 3 и объедините их, извлекая соответствующие значения.

with open('numpy.csv', 'wb') as f: 
     out_csv = csv.writer(f) 
     header = ['dim1','dim2','dim3','varn'] 
     out_csv.writerow(header) 
     bol1_indices = np.nonzero(bol1)[0] 
     bol2_indices = np.nonzero(bol2)[0] 
     bol3_indices = np.nonzero(bol3)[0] 
     out_csv.writerows(([a[i, k, l], dim1[i], dim2[k], dim3[l]] for i in bol1_indices for k in bol2_indices for l in bol3_indices)) 
+0

Спасибо, M4rtini. Это работает. И это примерно на 5-10% быстрее, чем петли. У вас есть другие намеки? – ucyo

+0

На самом деле, в этом случае я думаю, что большая часть времени выполнения находится от части записи в файл. Не уверен, как это ускорить. За исключением, возможно, покупки более быстрого hdd. – M4rtini

+0

Thx. Надеюсь, вы не возражаете, что я не считаю это решением. Я хочу подождать немного дольше. Может быть, некоторые эксперты netCDF могут намекнуть на специальные методы для этого ... – ucyo

0

Выполнение этого в python всегда будет медленным, потому что необработанные данные не находятся в том же формате, который вы хотите сохранить. Python должен будет создать индексы и сохранить одно значение в строке. Для чего вам нужен csv? Я рекомендую использовать ncdump, который очень быстро преобразуется в простой текстовый файл. Если вы должны использовать csv, вы можете использовать утилиту nc2text от FAN language utilities (см., Например, this page).

+0

Мне нужен формат csv для сохранения данных в SciDB. Я посмотрю в FAN и дам вам несколько отзывов. Любой опыт работы с SciDB? – ucyo

+0

@UCU, Нет, я не использовал SciDB. – tiago