嵌套 for 循环 python pandas 未按预期运行

Nested for loop python pandas not functioning as desired

为问题生成随机数据库的代码(最小可重现问题):

df_random = pd.DataFrame(np.random.random((2000,3)))
df_random['order_date'] = pd.date_range(start='1/1/2015', 
periods=len(df_random), freq='D')
df_random['customer_id'] = np.random.randint(1, 20, df_random.shape[0])
df_random

输出df_random

        0          1               2    order_date  customer_id
0   0.018473    0.970257    0.605428    2015-01-01    12
    ... ... ... ... ... ...
    1999    0.800139    0.746605    0.551530    2020-06-22  11

提取月和年平均唯一交易的代码

for y in (2015,2019):
for x in (1,13):
    df2 = df_random[(df_random['order_date'].dt.month == x)&(df_random['order_date'].dt.year== y)]
    df2.sort_values(['customer_id','order_date'],inplace=True)
    df2["days"] = df2.groupby("customer_id")["order_date"].apply(lambda x: (x - x.shift()) / np.timedelta64(1, "D"))
    df_mean=round(df2['days'].mean(),2)
    data2 = data.append(pd.DataFrame({'Mean': df_mean , 'Month': x, 'Year': y}, index=[0]), ignore_index=True)
    print(data2)

预期输出

  Mean         Month  Year
0   5.00          1  2015
    .......................
11  6.62         12  2015

..............Mean values of days after which one transaction occurs in order_date for years 2016 and 2017 Jan to Dec

36  6.03          1  2018
..........................
47  6.76         12  2018
48  8.40          1  2019
.......................
48  8.40         12  2019

基本上我想要从 2015 年 1 月到 2019 年 12 月的单个数据框

我得到的不是预期的输出,而是从 2015 年 1 月到 2018 年 12 月的数据帧,然后是 2015 年 1 月的数据,然后整个数据集从 2015 年到 2018 年再次重复多次。

请帮忙

试试这个:

data2 = pd.DataFrame([])
for y in range(2015,2020):
    for x in range(1,13):
        df2 = df_random[(df_random['order_date'].dt.month == x)&(df_random['order_date'].dt.year== y)]
        df_mean=df2.groupby("customer_id")["order_date"].apply(lambda x: (x - x.shift()) / np.timedelta64(1, "D")).mean().round(2)
        data2 = data2.append(pd.DataFrame({'Mean': df_mean , 'Month': x, 'Year': y}, index=[0]), ignore_index=True)

print(data2)

试试这个:

df_random.order_date = pd.to_datetime(df_random.order_date)
df_random = df_random.set_index(pd.DatetimeIndex(df_random['order_date']))
output = df_random.groupby(pd.Grouper(freq="M"))[[0,1,2]].agg(np.mean).reset_index()
output['month'] = output.order_date.dt.month
output['year'] = output.order_date.dt.year
output = output.drop('order_date', axis=1)
output

输出

0   1   2   month   year
0   0.494818    0.476514    0.496059    1   2015
1   0.451611    0.437638    0.536607    2   2015
2   0.476262    0.567519    0.528129    3   2015
3   0.519229    0.475887    0.612433    4   2015
4   0.464781    0.430593    0.445455    5   2015
... ... ... ... ... ...
61  0.416540    0.564928    0.444234    2   2020
62  0.553787    0.423576    0.422580    3   2020
63  0.524872    0.470346    0.560194    4   2020
64  0.530440    0.469957    0.566077    5   2020
65  0.584474    0.487195    0.557567    6   2020

避免任何循环,只需在 groupby 计算中包括

np.random.seed(1022020)
...
# ASSIGN MONTH AND YEAR COLUMNS, THEN SORT COLUMNS
df_random = (df_random.assign(month = lambda x: x['order_date'].dt.month,
                              year = lambda x: x['order_date'].dt.year)
                      .sort_values(['customer_id', 'order_date']))

# GROUP BY CALCULATION
df_random["days"] = (df_random.groupby(["customer_id", "year", "month"])["order_date"]
                              .apply(lambda x: (x - x.shift()) / np.timedelta64(1, "D")))

# FINAL MEAN AGGREGATION BY YEAR AND MONTH
final_df = (df_random.groupby(["year", "month"], as_index=False)["days"].mean().round(2)
                     .rename(columns={"days":"mean"}))

print(final_df.head())

#    year  month   mean
# 0  2015      1   8.43
# 1  2015      2   5.87
# 2  2015      3   4.88
# 3  2015      4  10.43
# 4  2015      5   8.12

print(final_df.tail())

#     year  month  mean
# 61  2020      2  8.27
# 62  2020      3  8.41
# 63  2020      4  8.81
# 64  2020      5  9.12
# 65  2020      6  7.00

对于多个聚合,替换单个 groupby.mean() to groupby.agg():

final_df = (df_random.groupby(["year", "month"], as_index=False)["days"]
                     .agg(['count', 'min', 'mean', 'median', 'max'])
                     .rename(columns={"days":"mean"}))

print(final_df.head())
#             count  min   mean  median   max
# year month
# 2015 1         14  1.0   8.43     5.0  25.0
#      2         15  1.0   5.87     5.0  17.0
#      3         16  1.0   4.88     5.0   9.0
#      4         14  1.0  10.43     7.5  23.0
#      5         17  2.0   8.12     8.0  17.0

print(final_df.tail())
#             count  min  mean  median   max
# year month
# 2020 2         15  1.0  8.27     6.0  21.0
#      3         17  1.0  8.41     7.0  16.0
#      4         16  1.0  8.81     7.0  20.0
#      5         16  1.0  9.12     7.0  22.0
#      6          7  2.0  7.00     7.0  17.0