在数据帧中应用单元格函数

时间:2015-08-08 14:44:17

标签: python numpy pandas

我有一个数据框,并希望根据公式替换每个单元格值 本月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

2 个答案:

答案 0 :(得分:3)

使用df.applymap(func),函数func仅传递给DataFrame 值。它没有传递相应的索引和列标签。所以我 看不到你可以在这里使用df.applymap的方式。

相反,您可以将df取消堆叠,并使用其索引df.stack().indexpd.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
  1. 这种方式可能会非常慢,具体取决于数据框的大小,但始终会返回正确的结果:

    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功能的问题在于他们不会 提供一种简单的方法来跟踪和访问两者列名称和索引 他们操作的当前单元格/行。

  2. 以下是使用apply的更快的代码,但如果同一列中有2个月或更多个月具有相同的值,则会提供错误的结果,因为{ {1}}返回np.wherenp.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])