在熊猫groupby的列内比较

时间:2019-04-18 18:21:41

标签: python pandas

让我们说我有一个数据框:

function reverse(array,item){
  let word = Math.ceil(array.length/2)
  array.splice(word,0,item)
  return array
}

console.log(reverse([1,2,4,5,6],3))

我想对这些数据进行分组,并比较组df = pd.DataFrame({'a':[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3], 'b':[2016, 2017, 2018, 2019, 2000, 2000, 2000, 2000, 2007, 2008, 2014]}) 中少于其他年份的年数。

在第1组中,2016年是第0年,然后2017年是第1年(或落后第1年)。

我尝试做:

a

但这要花很长时间。我想知道是否有更好的方法。我正在处理650万行。

预期输出:

df['c'] = df.groupby('a')['b'].apply(lambda x: [sum(y > x) for y in x]).reset_index(drop=False)

3 个答案:

答案 0 :(得分:1)

我会使用rank,然后再使用sub 1,我认为它非常易读,大约是其他答案的两倍,是原始方法的约3.5倍:

df.groupby(['a'])['b'].rank('min').sub(1)

#0     0.0
#1     1.0
#2     2.0
#3     3.0
#4     0.0
#5     0.0
#6     0.0
#7     0.0
#8     0.0
#9     1.0
#10    2.0

%timeit df.groupby(['a'])['b'].rank('min').sub(1)
#1.58 ms ± 61.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df.groupby('a')['b'].transform(lambda x: pd.factorize(x)[0])
#3.76 ms ± 330 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df.groupby('a')['b'].apply(lambda x: [sum(y > x) for y in x]).reset_index(drop=False)
#5.32 ms ± 129 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

答案 1 :(得分:1)

numpy解决方案

from scipy.stats import rankdata
np.concatenate([rankdata(x,method='min')for x in (np.split(df.b.values,np.flatnonzero(df.a.diff().fillna(0))))])-1

%timeit df.groupby(['a'])['b'].rank('min').sub(1)
1000 loops, best of 3: 845 µs per loop
%timeit df.groupby('a')['b'].transform(lambda x: pd.factorize(x)[0])
100 loops, best of 3: 1.77 ms per loop
%timeit df.groupby('a')['b'].apply(lambda x: [sum(y > x) for y in x]).reset_index(drop=False)
100 loops, best of 3: 2.71 ms per loop
%timeit np.concatenate([rankdata(x,method='min')for x in (np.split(df.b.values,np.flatnonzero(df.a.diff().fillna(0))))])-1
1000 loops, best of 3: 342 µs per loop

答案 2 :(得分:0)

干净高效的解决方案:

import pandas as pd

df = pd.DataFrame({'a':[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3], 
              'b':[2016, 2017, 2018, 2019, 2000, 2000, 2000, 2000, 2007, 2008, 2014]})

df=df.set_index('a')
df=df.sort_index()

quickmap={}

for index in df.index.unique():
    temphash={}
    val=0
    for i in df.loc[index]['b'].unique():
        temphash[i]=val
        val+=1
    quickmap[index]=temphash

df=df.reset_index()    

def toret(row):
    key=row['a']
    subkey=row['b']
    return quickmap[key][subkey]

df['c']=df.apply(toret,axis=1)