计算pandas Dataframe

时间:2016-06-16 05:10:25

标签: python datetime pandas group-by

我有以下数据框:

 data = [
("10/10/2016","A"),
("10/10/2016","B"),
("09/12/2016","B"),
("09/12/2016","A"),
("08/11/2016","A"),
("08/11/2016","C")] 

#Create DataFrame base
df = pd.DataFrame(data, columns=("Time","User"))

# Convert time column to correct format for time calculations
df["Time"] = pd.to_datetime(df["Time"], '%m/%d/%Y')

每行代表用户进行特定操作的时间。我想计算每个用户执行该特定操作的频率(以天为单位)。

假设用户A在2016年11月8日第一次交易,然后他在2016年12月9日再次交易,即大约30天后交易。然后,他在2016年10月10日,也就是他第二次交易后大约29天再次交易。因此,他的平均频率为(29 + 30)/ 2。

最有效的方法是什么?

提前致谢!

  • 更新

我编写了以下函数来计算我想要的输出。

from datetime import timedelta

def averagetime(a):
    numdeltas = len(a) - 1
    sumdeltas = 0

    i = 1
    while i < len(a):
        delta = abs((a[i] - a[i-1]).days)
        sumdeltas += delta
        i += 1

    if numdeltas > 1:
        avg = sumdeltas / numdeltas
    else:
        avg = 'NaN'  
    return avg

它正常工作,例如,当我通过整个“时间”列时:

averagetime(df["Time"])

但是当我尝试在分组后应用它时,它会给我一个错误。

df.groupby('User')['Time'].apply(averagetime)

有什么建议我可以解决上述问题吗?

2 个答案:

答案 0 :(得分:1)

您可以使用diff,按np.timedelta64(1,'D')转换为floatabssum

print (averagetime(df["Time"]))
12.0

su = ((df["Time"].diff() / np.timedelta64(1,'D')).abs().sum())
print (su / (len(df) - 1))
12.0

然后我将它应用于groupby,但是有必要的条件,因为:

  

ZeroDivisionError:浮点除零

print (df.groupby('User')['Time']
         .apply(lambda x: np.nan if len(x) == 1 
                                 else (x.diff()/np.timedelta64(1,'D')).abs().sum()/(len(x)-1)))

User
A    30.0
B    28.0
C     NaN
Name: Time, dtype: float64

答案 1 :(得分:0)

以@ Jezrael的回答为基础:

如果通过&#34;多久&#34;你的意思是 - 每个执行动作的用户之间经过了多长时间,然后这是一种方法:

import pandas as pd
import numpy as np

data = [
    ("10/10/2016","A"),
    ("10/10/2016","B"),
    ("09/12/2016","B"),
    ("09/12/2016","A"),
    ("08/11/2016","A"),
    ("08/11/2016","C"),
]

# Create DataFrame base
df = pd.DataFrame(data, columns=("Time","User"))

# Convert time column to correct format for time calculations
df["Time"] = pd.to_datetime(df["Time"], dayfirst=True)

# Group the DF by min, max and count the number of instances
grouped = (df.groupby("User").agg([np.max, np.min, np.count_nonzero])

           # This step is a bit messy and could be improved,
           # but we need the count as an int
           .assign(counter=lambda x: x["Time"]["count_nonzero"].astype(int))

           # Use apply to calculate the time between first and last, then divide by frequency
           .apply(lambda x: (x["Time"]["amax"] - x["Time"]["amin"]) / x["counter"].astype(int), axis=1)
           )

# Output the DF if using an interactive prompt
grouped

输出:

User    
A   20 days
B   30 days
C   0 days