2013-10-08 5 views
5

Привет всем,Панды интерполировать данные с единицами

Я смотрел на StackOverflow за пару лет, и это помогло мне много, так много, что я никогда не придется зарегистрироваться, прежде чем :)

Но сегодня я столкнулся с проблемой использования Python с Pandas и количеством (может быть, unum или pint). Я стараюсь сделать все возможное, чтобы сделать ясный пост, но так как это мой первый один, я прошу прощения, если что-то сбивает с толку, и будет пытаться исправить любую ошибку вы найдете :)


Я хочу, чтобы импортировать данные от источника и построить dataframe панды следующим образом:

import pandas as pd 
import quantities as pq 

depth = [0.0,1.1,2.0] * pq.m 
depth2 = [0,1,1.1,1.5,2] * pq.m 

s1 = pd.DataFrame(
     {'depth' : [x for x in depth]}, 
     index = depth) 

Это дает:

S1= 
    depth 
0.0 0.0 m 
1.1 1.1 m 
2.0 2.0 m 

Теперь я хочу расширьте данные до значений глубины 2: (очевидно, нет точки для интерполяции глубины по глубине, но это тест, прежде чем он усложнится).

s2 = s1.reindex(depth2) 

Это дает:

S2= 
     depth 
0.0 0.0 m 
1.0 NaN 
1.1 1.1 m 
1.5 NaN 
2.0 2.0 m 

До сих пор никаких проблем.


Но когда я пытаюсь интерполировать недостающие значения делают:

s2['depth'].interpolate(method='values') 

я получил следующее сообщение об ошибке:

C:\Python27\lib\site-packages\numpy\lib\function_base.pyc in interp(x, xp, fp, left, right) 
    1067   return compiled_interp([x], xp, fp, left, right).item() 
    1068  else: 
-> 1069   return compiled_interp(x, xp, fp, left, right) 
    1070 
    1071 
TypeError: Cannot cast array data from dtype('O') to dtype('float64') according to the rule 'safe' 

Я понимаю, что интерполяция с NumPy не работает на объекте.


Но если я пытаюсь теперь интерполировать недостающие значения, понижая единицы, это работает:

s3 = s2['depth'].astype(float).interpolate(method='values') 

Это дает:


Как я могу получить назад блок в колонке глубины?

Я не могу найти какой-либо трюк, чтобы положить обратно блок ...

Любая помощь будет принята с благодарностью. Спасибо

+0

Почему бы не размножить все в нужном столбце на 1 метр? –

+0

вы имеете в виду как 's2 ['depth'] * pq.m'? Это не работает. Он всегда игнорирует устройство. Не важно, какую комбинацию я стараюсь. – Julien

+1

Были некоторые разговоры о поддержке этого. См. Здесь проблему github: https://github.com/pydata/pandas/issues/2494 – TomAugspurger

ответ

0

Ok Я нашел решение, мог бы не лучший, но для моей проблемы это работает отлично:

import pandas as pd 
import quantities as pq 

def extendAndInterpolate(input, newIndex): 
""" Function to extend a panda dataframe and interpolate 
""" 
output = pd.concat([input, pd.DataFrame(index=newIndex)], axis=1) 

for col in output.columns: 
    # (1) Try to retrieve the unit of the current column 
    try: 
     # if it succeeds, then store the unit 
     unit = 1 * output[col][0].units  
    except Exception, e: 
     # if it fails, which means that the column contains string 
     # then return 1 
     unit = 1 

    # (2) Check the type of value. 
    if isinstance(output[col][0], basestring): 
     # if it's a string return the string and fill the missing cell with this string 
     value = output[col].ffill() 
    else: 
     # if it's a value, to be able to interpolate, you need to: 
     # - (a) dump the unit with astype(float) 
     # - (b) interpolate the value 
     # - (c) add again the unit 
     value = [x*unit for x in output[col].astype(float).interpolate(method='values')] 
    # 
    # (3) Returned the extended pandas table with the interpolated values  
    output[col] = pd.Series(value, index=output.index) 
# Return the output dataframe 
return output 

Тогда:

depth = [0.0,1.1,2.0] * pq.m 
depth2 = [0,1,1.1,1.5,2] * pq.m 

s1 = pd.DataFrame(
     {'depth' : [x for x in depth]}, 
     index = depth) 

s2 = extendAndInterpolate(s1, depth2) 

Результат:

s1 
    depth 
0.0 0.0 m 
1.1 1.1 m 
2.0 2.0 m 

s2  
    depth 
0.0 0.0 m 
1.0 1.0 m 
1.1 1.1 m 
1.5 1.5 m 
2.0 2.0 m 

Спасибо вам помочь.

2

Вот способ сделать то, что вы хотите.

Разделяющаяся величин и создать набор из 2 столбцов для каждой величины

In [80]: df = concat([ col.apply(lambda x: Series([x.item(),x.dimensionality.string], 
         index=[c,"%s_unit" % c])) for c,col in s1.iteritems() ]) 

In [81]: df 
Out[81]: 
    depth depth_unit 
0.0 0.0   m 
1.1 1.1   m 
2.0 2.0   m 

In [82]: df = df.reindex([0,1.0,1.1,1.5,2.0]) 

In [83]: df 
Out[83]: 
    depth depth_unit 
0.0 0.0   m 
1.0 NaN  NaN 
1.1 1.1   m 
1.5 NaN  NaN 
2.0 2.0   m 

интерполировать

In [84]: df['depth'] = df['depth'].interpolate(method='values') 

распространения информации о блоках

In [85]: df['depth_unit'] = df['depth_unit'].ffill() 

In [86]: df 
Out[86]: 
    depth depth_unit 
0.0 0.0   m 
1.0 1.0   m 
1.1 1.1   m 
1.5 1.5   m 
2.0 2.0   m 
+0

Спасибо Джеффу за ваш ответ. Я увижу, как я могу это реализовать, потому что у меня будет несколько столбцов с разными параметрами и единицами. Я все еще смотрю, что я могу найти способ получить панда данных с единицами в, после интерполяции. Возможно, мне нужно создать промежуточный фрейм с не-единицей и построить окончательный фрейм с интерполированными значениями и единицами. – Julien

+0

yep ... это была проблема w.r.t в библиотеке величин в течение довольно долгого времени. Его нетривиально переносить этот тип метаданных без крупных изменений. Но если вы придумаете хорошую публикацию pls на github. – Jeff

+0

Спасибо Джефф, я добавил свое решение ниже. Не уверен, достаточно ли это для python для github :) Я очень новичок в python, но люблю его. – Julien

Смежные вопросы