我是python和pandas的新手,对于如何编写一个简短的函数有一个基本问题,该函数需要一个pd.Dataframe并返回按月分组的相对值。
示例数据:
import pandas as pd
from datetime import datetime
import numpy as np
date_rng = pd.date_range(start='2019-01-01', end='2019-03-31', freq='D')
df = pd.DataFrame(date_rng, columns=['date'])
df['value_in_question'] = np.random.randint(0,100,size=(len(date_rng)))
df.set_index('date',inplace=True)
df.head()
value_in_question
date
2019-01-01 40
2019-01-02 86
2019-01-03 46
2019-01-04 75
2019-01-05 35
def absolute_to_relative(df):
"""
set_index before using
"""
return df.div(df.sum(), axis=1).mul(100)
relative_df = absolute_to_relative(df)
relative_df.head()
value_in_question
date
2019-01-01 0.895055
2019-01-02 1.924368
2019-01-03 1.029313
2019-01-04 1.678228
2019-01-05 0.783173
与其获取列总和并以此来划分每一行, 我想每个月汇总一下。最终df应该具有相同的 形状和形式,但行值与月份的总和有关。
旧:
value_in_question
date
"2019-01-01" value/colum_sum * 100
新:
value_in_question
date
"2019-01-01" value/month_sum * 100
所以我尝试了以下操作,该操作返回value_in_question的NA:
def absolute_to_relative_agg(df, agg):
"""
set_index before using
"""
return df.div(df.groupby([pd.Grouper(freq=agg)]).sum(), axis=1)
relative_df = absolute_to_relative(df,'M')
value_in_question
date
2019-01-01 NaN
2019-01-02 NaN
2019-01-03 NaN
2019-01-04 NaN
2019-01-05 NaN
答案 0 :(得分:3)
使用GroupBy.transform
代替具有与原始DatatimeIndex
相同的def absolute_to_relative_agg(df, agg):
"""
set_index before using
"""
return df.div(df.groupby([pd.Grouper(freq=agg)]).transform('sum'))
relative_df = absolute_to_relative_agg(df, 'M')
的Series / DateFrame进行聚合,因此可能的划分:
relative_df = df.pipe(absolute_to_relative_agg, 'M')
print (relative_df)
value_in_question
date
2019-01-01 0.032901
2019-01-02 0.045862
2019-01-03 0.048853
2019-01-04 0.008475
2019-01-05 0.041376
...
2019-03-27 0.062049
2019-03-28 0.002165
2019-03-29 0.048341
2019-03-30 0.007937
2019-03-31 0.015152
[90 rows x 1 columns]
调用功能的另一种方法是DataFrame.pipe
:
ratio
答案 1 :(得分:0)
对于总和,您可以groupby
索引月份:
In [31]: month_sum = df.groupby(df.index.strftime('%Y%m')).sum()
...: month_sum
...:
Out[31]:
value_in_question
201901 1386
201902 1440
201903 1358
然后您可以使用.map
将月份与DataFrame的正确行对齐:
In [32]: map_sum = df.index.strftime('%Y%m').map(month_sum['value_in_question'])
...: map_sum
...:
Out[32]:
Int64Index([1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386,
1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386,
1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1440, 1440,
1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440,
1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440,
1440, 1440, 1440, 1440, 1358, 1358, 1358, 1358, 1358, 1358, 1358,
1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358,
1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358,
1358, 1358],
dtype='int64')
然后您只需要进行除法:
In [33]: df['value_in_question'].div(map_sum)
Out[33]:
date
2019-01-01 0.012987
2019-01-02 0.018759
2019-01-03 0.000000
2019-01-04 0.056277
2019-01-05 0.019481
...
2019-03-27 0.031664
2019-03-28 0.007364
2019-03-29 0.050074
2019-03-30 0.033873
2019-03-31 0.005155
Name: value_in_question, Length: 90, dtype: float64
答案 2 :(得分:0)
将 Grouper 与 freq ='M'一起使用。
代码是:
relative_df = df.groupby(pd.Grouper(freq='M'))\
.value_in_question.apply(lambda x: x.div(x.sum()).mul(100))
它返回索引与原始DataFrame中相同的 Series 且值等于当月相对的 value_in_question 。