我有一个数据框,并希望根据公式替换每个单元格值
本月new_val = current_val/#days
。假设数据框看起来像:
2012 2013 2014
Jan 10 12 11
Feb 8 9 10
Mar 11 11 13
然后,如果2012年1月的天数是31,则对应于2012年1月的新单元格值将是10/31。同样,2014年3月的价值将是13/31,依此类推。
我正在考虑应用applymap
函数,但我正在努力学习语法:
df.applymap(lambda x: x/(monthrange(A,B)[1]))
其中A =年,B =月。我想知道是否有人可以帮助我为A和B提供适当的索引。
输出将是:
2012 2013 2014
Jan 0.3226 0.3870 0.3548
Feb 0.2758 0.3214 0.3571
Mar 0.3548 0.3548 0.4193
答案 0 :(得分:3)
使用df.applymap(func)
,函数func
仅传递给DataFrame
值。它没有传递相应的索引和列标签。所以我
看不到你可以在这里使用df.applymap
的方式。
相反,您可以将df
取消堆叠,并使用其索引df.stack().index
和pd.to_datetime
将索引和列标签解析为日期:
result = df.stack()
# Jan 2012 10
# 2013 12
# 2014 11
# Feb 2012 8
# 2013 9
# 2014 10
# Mar 2012 11
# 2013 11
# 2014 13
# dtype: int64
dates = pd.to_datetime([' '.join(item) for item in result.index])
# DatetimeIndex(['2012-01-01', '2013-01-01', '2014-01-01', '2012-02-01',
# '2013-02-01', '2014-02-01', '2012-03-01', '2013-03-01',
# '2014-03-01'],
# dtype='datetime64[ns]', freq=None, tz=None)
然后使用DatetimeIndex.days_in_month
属性查找数字
每个月的日子:
days = dates.days_in_month
# array([31, 31, 31, 29, 28, 28, 31, 31, 31], dtype=int32)
现在将result
除以每月的天数:
In [140]: result/days
Out[140]:
Jan 2012 0.322581
2013 0.387097
2014 0.354839
Feb 2012 0.275862
2013 0.321429
2014 0.357143
Mar 2012 0.354839
2013 0.354839
2014 0.419355
dtype: float64
并取消堆栈以获得所需的结果:
(df.stack()/days).unstack()
import numpy as np
import pandas as pd
df = pd.DataFrame({'2012': [10, 8, 11], '2013': [12, 9, 11], '2014': [11, 10, 13]},
index='Jan Feb Mar'.split())
result = df.stack()
dates = pd.to_datetime([' '.join(item) for item in result.index])
days = dates.days_in_month
result = (result / days).unstack()
print(result)
产量
2012 2013 2014
Jan 0.322581 0.387097 0.354839
Feb 0.275862 0.321429 0.357143
Mar 0.354839 0.354839 0.419355
对于旧版本的Pandas(v.0.16之前),您可以使用
days = (dates + pd.DateOffset(months=1, days=-1)).day
而不是
days = dates.days_in_month
查找每个月的天数。
答案 1 :(得分:2)
我将展示的两种方式都需要这本词典并导入:
names_to_months = {'Jan': 1, 'Feb': 2, 'Mar': 3, .... }
import calendar
这种方式可能会非常慢,具体取决于数据框的大小,但始终会返回正确的结果:
for index in df.index:
for column in df.columns:
df[column] = df[column].astype(float)
df.at[index, column] = round(df.ix[index, column] / calendar.monthrange(int(column), names_to_months[index])[1], 4)
apply
/ map
/ applymap
功能的问题在于他们不会
提供一种简单的方法来跟踪和访问两者列名称和索引
他们操作的当前单元格/行。
以下是使用apply
的更快的代码,但如果同一列中有2个月或更多个月具有相同的值,则会提供错误的结果,因为{ {1}}返回np.where
个np.array
的索引,它找到x
的值,但是没有办法存储它,并在下次遇到相同时使用下一个索引x
值:
for col in list(df.columns):
df[col] = df[col].apply(lambda x: x / calendar.monthrange(int(col), names_to_months[df.index[np.where(df[col] == x)[0][0]]])[1])