基于pandas

时间:2018-02-20 05:24:29

标签: python pandas

我编写了一个数据框来说明我的问题。说,我有三个病人:'a','b','c'。我们在三个不同的时间点(t1,t2,t3)得到了这些患者的结果。我需要的是创建另一个列'Fold',这是从t1开始的倍数变化。由于患者'c'在t1没有任何结果,因此其对t1的倍数变化应为nan。 以下是代码:

df = pd.DataFrame ({ \
                   'time': np.repeat(['t1','t2','t3'], [2,3,3]),
                   'id': ['a', 'b', 'a', 'b', 'c', 'a', 'b', 'c'],
                   'result':np.random.randint(10,20,size=8) })
# create indicator column has_t1: if a patient  has t1: 1 if not: 0
df['is_t1'] = np.where(df['time']=='t1', 1, 0)
df['has_t1'] = df.groupby('id')['is_t1'].transform(sum)
# create fold change column
df['fold'] =df.sort_values(['id', 'time']).groupby('id').apply(lambda x: x['result']/x['result'].iloc[0] if x['has_t1'].iloc[0]==1 else np.nan)

我收到了错误:

AttributeError: 'float' object has no attribute 'index'

我想要的输出类似于:

        Fold
id time          
a  t1    1.000000
   t2    1.545455
   t3    1.000000
b  t1    1.000000
   t2    1.062500
   t3    0.937500
c  
   t2         NaN
   t3         NaN

有谁知道我做错了什么?感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

这是一种不涉及指标列的替代方法。首先,unstack然后重新stack而不删除NaN:

df = df.set_index(['id', 'time']).unstack().stack(dropna=False) 
df

         result
id time        
a  t1      12.0
   t2      18.0
   t3      13.0
b  t1      13.0
   t2      11.0
   t3      13.0
c  t1       NaN
   t2      13.0
   t3      17.0

接下来,拨打groupby + transform + head并将df.result除以此输出:

df['result'] /= df.groupby(level=0).result.transform('head', 1)    
df

           result
id time          
a  t1    1.000000
   t2    1.545455
   t3    1.000000
b  t1    1.000000
   t2    1.062500
   t3    0.937500
c  t1         NaN
   t2         NaN
   t3         NaN

答案 1 :(得分:1)

嗯,还有另一种方式

s=df.set_index(['id','time']).reindex(pd.MultiIndex.from_product([set(df.id.tolist()),set(df.time.tolist())]))

s=s.sort_index()
s.result.div(s.groupby(level=0).result.nth(0),level=0)
Out[256]: 
a  t1    1.000000
   t2    1.900000
   t3    1.800000
b  t1    1.000000
   t2    0.736842
   t3    0.578947
c  t1         NaN
   t2         NaN
   t3         NaN
Name: result, dtype: float64

答案 2 :(得分:0)

使用groupby,apply和stack的另一种方法。

def fold(x):
    df_tmp = x.set_index('time')    
    df_tmp = df_tmp.reindex(df_tmp.index.union(['t1']))
    return df_tmp.result.div(df_tmp.loc['t1','result'])

df.groupby('id').apply(fold).stack(dropna=False)
Out[229]: 
id  result
a   t1        1.000000
    t2        0.923077
    t3        0.923077
b   t1        1.000000
    t2        1.300000
    t3        1.400000
c   t1             NaN
    t2             NaN
    t3             NaN