Python 计算组内移动中值

Python 计算组内移动中值,python,pandas,pandas-groupby,median,rolling-computation,Python,Pandas,Pandas Groupby,Median,Rolling Computation,我想在4天前对价格列执行滚动中值,数据将按日期分组。所以基本上我想把一天的价格和4天的所有价格取回来,然后计算出这些值的中间值 以下是示例数据: id date price 1637027 2020-01-21 7045204.0 280955 2020-01-11 3590000.0 782078 2020-01-28 2600000.0 1921717 2020-02-17 5500000.0 1280579 2020-01-23 869000.0 21

我想在4天前对价格列执行滚动中值,数据将按日期分组。所以基本上我想把一天的价格和4天的所有价格取回来,然后计算出这些值的中间值

以下是示例数据:

id      date        price
1637027 2020-01-21  7045204.0
280955  2020-01-11  3590000.0
782078  2020-01-28  2600000.0
1921717 2020-02-17  5500000.0
1280579 2020-01-23  869000.0
2113506 2020-01-23  628869.0
580638  2020-01-25  650000.0
1843598 2020-02-29  969000.0
2300960 2020-01-24  5401530.0
1921380 2020-02-19  1220000.0
853202  2020-02-02  2990000.0
1024595 2020-01-27  3300000.0
565202  2020-01-25  3540000.0
703824  2020-01-18  3990000.0
426016  2020-01-26  830000.0
我与rolling和groupby的结合非常接近:

df.groupby('date').rolling(window = 4, on = 'date')['price'].median()
但这似乎给每个索引值增加了一行,根据中值定义,我无法以某种方式合并这些行,从而为每行生成一个结果

现在的结果如下所示:

date        date      
2020-01-10  2020-01-10          NaN
            2020-01-10          NaN
            2020-01-10          NaN
            2020-01-10    3070000.0
            2020-01-10    4890000.0
                            ...    
2020-03-11  2020-03-11    4290000.0
            2020-03-11    3745000.0
            2020-03-11    3149500.0
            2020-03-11    3149500.0
            2020-03-11    3149500.0
Name: price, Length: 389716, dtype: float64
它似乎只是删除了3个第一个值,然后只是打印价格值

是否可以在每个日期获得一个滞后/移动中值?

您可以使用5天的频率窗口滚动来获得今天和最后4天,然后删除重复项以保持每天的最后一行。首先创建一个副本,如果要保留原始副本,请按日期对_值进行排序,并确保日期列为datetime

#sort and change to datetime
df_f = df[['date','price']].copy().sort_values('date')
df_f['date'] = pd.to_datetime(df_f['date'])

#create the column rolling
df_f['price'] = df_f.rolling('5D', on='date')['price'].median()

#drop_duplicates and keep the last row per day
df_f = df_f.drop_duplicates(['date'], keep='last').reset_index(drop=True)

print (df_f)

         date      price
0  2020-01-11  3590000.0
1  2020-01-18  3990000.0
2  2020-01-21  5517602.0
3  2020-01-23   869000.0
4  2020-01-24  3135265.0
5  2020-01-25  2204500.0
6  2020-01-26   849500.0
7  2020-01-27   869000.0
8  2020-01-28  2950000.0
9  2020-02-02  2990000.0
10 2020-02-17  5500000.0
11 2020-02-19  3360000.0
12 2020-02-29   969000.0
您可以使用5天的频率窗口滚动来获得今天和最后4天,然后删除重复项以保持每天的最后一行。首先创建一个副本,如果要保留原始副本,请按日期对_值进行排序,并确保日期列为datetime

#sort and change to datetime
df_f = df[['date','price']].copy().sort_values('date')
df_f['date'] = pd.to_datetime(df_f['date'])

#create the column rolling
df_f['price'] = df_f.rolling('5D', on='date')['price'].median()

#drop_duplicates and keep the last row per day
df_f = df_f.drop_duplicates(['date'], keep='last').reset_index(drop=True)

print (df_f)

         date      price
0  2020-01-11  3590000.0
1  2020-01-18  3990000.0
2  2020-01-21  5517602.0
3  2020-01-23   869000.0
4  2020-01-24  3135265.0
5  2020-01-25  2204500.0
6  2020-01-26   849500.0
7  2020-01-27   869000.0
8  2020-01-28  2950000.0
9  2020-02-02  2990000.0
10 2020-02-17  5500000.0
11 2020-02-19  3360000.0
12 2020-02-29   969000.0

这是一个循序渐进的过程。可能有更有效的方法来获得你想要的东西。注意,如果您有日期的时间信息,则需要在按日期分组之前删除该信息

import pandas as pd
import statistics as stat
import numpy as np

# Replace with you data import
df = pd.read_csv('random_dates_prices.csv')

# Convert your date to a datetime
df['date'] = pd.to_datetime(df['date'])

# Sort your data by date
df = df.sort_values(by = ['date'])

# Create group by object
dates = df.groupby('date')

# Reformat dataframe for one row per day, with prices in a nested list
df = pd.DataFrame(dates['price'].apply(lambda s: s.tolist()))

# Extract price lists to a separate list
prices = df['price'].tolist()

# Initialize list to store past four days of prices for current day
four_days = []

# Loop over the prices list to combine the last four days to a single list
for i in range(3, len(prices), 1):
    x = i - 1
    y = i - 2
    z = i - 3
    four_days.append(prices[i] + prices[x] + prices[y] + prices[z])

# Initialize a list to store median values
medians = []

# Loop through four_days list and calculate the median of the last for days for the current date
for i in range(len(four_days)):
    medians.append(stat.median(four_days[i]))

# Create dummy zero values to add lists create to dataframe    
four_days.insert(0, 0)
four_days.insert(0, 0)
four_days.insert(0, 0)
medians.insert(0, 0)
medians.insert(0, 0)
medians.insert(0, 0)

# Add both new lists to data frames
df['last_four_day_prices'] = four_days
df['last_four_days_median'] = medians

# Replace dummy zeros with np.nan
df[['last_four_day_prices', 'last_four_days_median']] = df[['last_four_day_prices', 'last_four_days_median']].replace(0, np.nan)

# Clean data frame so you only have a single date a median value for past four days
df_clean = df.drop(['price', 'last_four_day_prices'], axis=1)

这是一个循序渐进的过程。可能有更有效的方法来获得你想要的东西。注意,如果您有日期的时间信息,则需要在按日期分组之前删除该信息

import pandas as pd
import statistics as stat
import numpy as np

# Replace with you data import
df = pd.read_csv('random_dates_prices.csv')

# Convert your date to a datetime
df['date'] = pd.to_datetime(df['date'])

# Sort your data by date
df = df.sort_values(by = ['date'])

# Create group by object
dates = df.groupby('date')

# Reformat dataframe for one row per day, with prices in a nested list
df = pd.DataFrame(dates['price'].apply(lambda s: s.tolist()))

# Extract price lists to a separate list
prices = df['price'].tolist()

# Initialize list to store past four days of prices for current day
four_days = []

# Loop over the prices list to combine the last four days to a single list
for i in range(3, len(prices), 1):
    x = i - 1
    y = i - 2
    z = i - 3
    four_days.append(prices[i] + prices[x] + prices[y] + prices[z])

# Initialize a list to store median values
medians = []

# Loop through four_days list and calculate the median of the last for days for the current date
for i in range(len(four_days)):
    medians.append(stat.median(four_days[i]))

# Create dummy zero values to add lists create to dataframe    
four_days.insert(0, 0)
four_days.insert(0, 0)
four_days.insert(0, 0)
medians.insert(0, 0)
medians.insert(0, 0)
medians.insert(0, 0)

# Add both new lists to data frames
df['last_four_day_prices'] = four_days
df['last_four_days_median'] = medians

# Replace dummy zeros with np.nan
df[['last_four_day_prices', 'last_four_days_median']] = df[['last_four_day_prices', 'last_four_days_median']].replace(0, np.nan)

# Clean data frame so you only have a single date a median value for past four days
df_clean = df.drop(['price', 'last_four_day_prices'], axis=1)


df.rollingwindow=4,on='date'['price'].median?似乎只是删除了前3行,然后打印每个索引的价格,而不是dayoh,现在我明白了,每个日期都有不止一行,让我看看……除了迭代之外,还没有找到一种方法,这里是:pd.DataFrame[[x,df[df['date']=x-pd.Timedelta'4d']['price'].median]用于df['date']中的x,columns=['date','4d_median'].drop_duplicatesdf.rollingwindow=4,on='date'['price'].median?似乎只是删除前3行,然后按指数打印价格,而不是dayoh,现在我明白了,每个日期都有不止一行,让我想想……没有找到一种方法,但需要迭代,这里是:pd.DataFrame[[x,df[date']=x-pd.Timedelta'4d']['price'].median]对于df['date']]中的x,列=['date','4d_median']。删除重复项试图对另一个列age执行相同操作,我需要在滚动之前过滤这些值。我尝试的方式是:df_f['medAge']=df_f[df_f['age']>=35]。滚动'5D',日期'['age'].median,但它有时会产生正确的结果,有时会产生NaN,尽管有值。你知道为什么吗?@Musisak这是因为索引对齐。假设df_f总共有10行,但由于过滤器,df_f[df_f['age']>=35]只有6行,然后在滚动之后仍然是6行,但是在df_f中分配这6个值,有10行,缺少的索引用NaN填充。检查NaN是否仅在年龄小于35的地方!尝试对另一列年龄做同样的操作,我需要在滚动之前过滤这些值。我尝试了:df_f['medAge']=df_f[df_f['age']>=35]。在='date'['age']上滚动'5D',中位数,但有时会产生正确的结果,有时会产生NaN,尽管有值。你知道为什么吗?@Musisak这是因为索引对齐。假设df_f总共有10行,但由于过滤器,df_f[df_f['age']>=35]只有6行,滚动后仍然是6行,但是在df_f中分配这6个值,有10行,缺少的索引用NaN填充。检查NaN是否只在年龄小于35的地方!这很有趣,但如果没有所有日期,它将失败。因为当你做价格[i]+价格[x]+价格[y]+价格[z]您可能会获取不在正确时间范围内的天数的价格。我认为如果不包括所有日期,它不会失败。我生成的数据没有所有日期,这是可行的。因为我们按日期对数据框进行排序,数据中的任何日期都将是有序的。然后,当价格信息提取到列表中时,我们不再有日期,等等列出价格表的日期。因此,当我们循环查看价格时,我们会从列表索引中减去,列表索引不代表一天。代码有效,但我对结果有一些怀疑。请使用OP数据亲自尝试一下:对于2020-02-17日期,只有一个值为5500000,最接近的日期是2020-02-02,而不是4天前。所以过去4天的中位数是5500000,但用你的方法,我得到3145000.0,因为它使用了列表中前一个可用日期的值,即使它们不在4天之内。是的,你是正确的。我们对ask的解读不同。如果ask是过去4天的中位数,无论数据中是否存在这些日期,t他不会提供你想要的结果。这很有趣,但如果你没有所有的日期,它就会失败
. 因为当你做价格[i]+价格[x]+价格[y]+价格[z]时,你会在不正确的时间范围内获取几天的价格。我认为如果不包括所有日期,它不会失败。我生成的数据没有所有的日期,这是有效的。因为我们按日期对数据框进行排序,所以数据中的任何日期都是有序的。然后,当价格信息被提取到列表中时,我们不再有日期,只有日期价格列表。因此,当我们循环遍历价格时,我们从列表索引中减去,这并不代表一天。代码是有效的,但我对结果有一些怀疑。用OP数据自己尝试一下:对于日期2020-02-17,只有一个值为5500000,最接近的日期是2020-02-02,而不是4天前。所以,过去4天的中位数是5500000,但用你的方法,我得到3145000.0,因为它使用了列表中前一个日期的值,即使它们不在4天之内。是的,你是正确的。我们的阅读方式不同。如果ask是过去四天的中位数,不管数据中是否存在这些日期,这都不会提供您想要的结果。