财新传媒 财新传媒

阅读:0
听报道

做宏观经济研究,做数据清洗是第一步。现在通过AI辅助编程,可以为我们提供一些便利,本文梳理两个案例。

一、填充春节缺失值

因为春节,很多经济数据往往只公布1-2月合并数据,这有时会造成2月单月数据缺失,比如下图中的制造业增加值同比,需要手动将1-2月累计同比,复制到2月当月同比。我们尝试通过AI编程实现。

向AI描述我们的需求

我有一个2列的DataFrame数据,index是月份,格式是yyyy-mm,第1列数据的部分数据缺失,我希望把第1列的数据补全,补全的数据是第2列的对应数据,请用Python实现

以下是AI给的程序,还附带了说明

好的,您可以使用`fillna`方法来实现将第一列的缺失值填充为第二列对应的值。具体代码如下:


import pandas as pd
# 读取数据
df = pd.read_csv('your_file.csv', index_col=0)
# 使用第二列的数据填充第一列的缺失值
df.iloc[:, 0] = df.iloc[:, 0].fillna(df.iloc[:, 1])
# 输出结果
print(df)


其中,your_file.csv是您的数据文件名。这段代码会读取该文件,并将第一列的缺失值填充为第二列对应的值。最后输出结果。
 

AI给的这段代码的核心,是使用.fillna()来填充缺失值,能否成功呢?我们来实验一下,

缺失值填充前

缺失值填充后

从结果上可以看到,2022年2月和2023年2月,两个单月缺失值,都使用累计值做了填充,实现了我们的需求。

补齐1月日期,用2月数据填充

我有一个DataFrame数据,index是月份,格式是yyyy-mm,其中,1月的index缺失,需要补全所有的月份,并用缺失值的后一个观测值,填充缺失值,请用Python实现

好的,您可以使用resample方法和fillna方法来实现将缺失值填充为后一个观测值,并补全所有的月份。具体代码如下:

import pandas as pd
# 读取数据
df = pd.read_csv('your_file.csv', index_col=0)
# 将index转换为DatetimeIndex对象
df.index = pd.to_datetime(df.index)
# 重新采样,以补全所有的月份
df_resampled = df.resample('M').asfreq()
# 使用后一个观测值填充缺失值
df_filled = df_resampled.fillna(method='bfill')
# 输出结果
print(df_filled)

其中,your_file.csv是您的数据文件名。这段代码会读取该文件,并将index转换为DatetimeIndex对象。然后使用resample方法重新采样,以补全所有的月份。接着使用fillna方法将缺失值填充为后一个观测值。最后输出结果
 

缺失值填充前

缺失值填充后


从结果上看,右侧缺失值填充后,一方面填充了2022年2月和2023年2月的缺失值,也补充了2022年1月和2023年1月的index缺失,所以多了两行,很好的满足了我们的需求,而且代码很简洁。

二、根据同比调整绝对值序列

我们知道,由于统计样本的差异,我们使用官方发布的绝对值计算的同比,有时与官方发布的同比,并不匹配,比较典型的比如固定资产投资额的累计值自算同比,与官方发布的累计同比,存在较大差异。这种情况,我们如果想计算单月同比,则需要根据官方同比,选定一个基期,折算一个绝对值序列。

首先,填充缺失值,以2月累计同比填充1月缺失值,以2月累计值的一半填充1月缺失值

我有一个DataFrame数据,index是月份,格式是yyyy-mm,其中,1月的index缺失,我需要补全所有的月份,其中,第1列的缺失值用后一个观测值的一半填充,第2列的缺失值用后一个观测值填充,请用Python实现

好的,您可以使用resample方法和fillna方法来实现将缺失值填充为后一个观测值,并补全所有的月份。对于第1列的缺失值,您可以使用fillna方法和bfill方法来实现将缺失值填充为后一个观测值的一半。具体代码如下:

import pandas as pd
# 读取数据
df = pd.read_csv('your_file.csv', index_col=0)
# 将index转换为DatetimeIndex对象
df.index = pd.to_datetime(df.index)
# 重新采样,以补全所有的月份
df_resampled = df.resample('M').asfreq()
# 使用后一个观测值填充第2列的缺失值
df_resampled.iloc[:, 1] = df_resampled.iloc[:, 1].fillna(method='bfill')
# 使用后一个观测值的一半填充第1列的缺失值
df_resampled.iloc[:, 0] = df_resampled.iloc[:, 0].fillna(df_resampled.iloc[:, 0].shift(1) / 2)
# 输出结果
print(df_resampled)

其中,your_file.csv是您的数据文件名。这段代码会读取该文件,并将index转换为DatetimeIndex对象。然后使用resample方法重新采样,以补全所有的月份。接着使用fillna方法将第2列的缺失值填充为后一个观测值,将第1列的缺失值填充为后一个观测值的一半。最后输出结果。
 

我们来实验一下,

缺失值填充前

缺失值填充后

从结果上可以看到,1月缺失的时间序列填充了,1月的累计同比缺失值用2月数据填充了,但是1月的累计值缺失值出现了错误,使用的是12月的值的一半。这是因为我们把数据按照时间进行了逆序排列,正常情况下是不需要修改的。

那么我们把上述程序中的df.iloc[:, 0].shift(1)改成df.iloc[:, 0].shift(-1),改完之后再跑一下,结果就没问题了。

缺失值填充前

缺失值填充后

然后,选定基期来生成绝对值序列

我现在有一个dataframe数据,时间index是月度数据,时间格式是xxxx-xx,第1列是数值,第2列是同比,我需要以某一年为基期,通过同比数据向前和向后外推出其他值,基期使用参数设定,请用Python实现

import pandas as pd

def extrapolate_data(df, base_year, base_month):
    # 将时间字符串转换为pandas的时间戳
    df.index = pd.to_datetime(df.index, format="%Y-%m")

    # 获取基准年月的时间戳
    base_date = pd.Timestamp(year=base_year, month=base_month, day=1)

    # 向前推算
    current_date = base_date - pd.DateOffset(months=1)
    while current_date in df.index:
        df.loc[current_date, '第1列'] = df.loc[current_date + pd.DateOffset(months=1), '第1列'] / (1 + df.loc[current_date, '第2列'] / 100)
        current_date -= pd.DateOffset(months=1)

    # 向后推算
    current_date = base_date + pd.DateOffset(months=1)
    while current_date in df.index:
        df.loc[current_date, '第1列'] = df.loc[current_date - pd.DateOffset(months=1), '第1列'] * (1 + df.loc[current_date, '第2列'] / 100)
        current_date += pd.DateOffset(months=1)

    return df

# 示例数据
data = {'时间': ['2020-12', '2021-01', '2021-02', '2021-03'],
        '第1列': [None, 100, None, None],
        '第2列': [0.03, 0.02, 0.05, -0.02]}
df = pd.DataFrame(data)
df.set_index('时间', inplace=True)

# 设置基准年月
base_year = 2021
base_month = 1

# 计算结果
result = extrapolate_data(df, base_year, base_month)
print(result)
 

我们仔细读程序,我们发现,因为我们给出的是12个月的同比来生成绝对值,AI可能习惯的是根据环比来生成,所以AI给的程序,时间间隔是1个月,我们需要手动调整一下,比如,向后推算的时候:

current_date = base_date + pd.DateOffset(months=1)要改成current_date = base_date + pd.DateOffset(months=12)

另外,因为我们的列名是不固定的,所以需要使用.iloc来定位,而不是.loc,所以

df.loc[current_date, '第1列'] = df.loc[current_date - pd.DateOffset(months=1), '第1列'] * (1 + df.loc[current_date, '第2列'] / 100)要改成

df.loc[current_date].iloc[0] = df.loc[[current_date + pd.DateOffset(months=12)]].iloc[0, 0] / (1 + df.loc[[current_date + pd.DateOffset(months=12)]].iloc[0, 1] / 100)

我们跑了一下程序,发现结果没有出来,我们检查了一下,发现是base_date = pd.Timestamp(year=base_year, month=base_month, day=1)取的是每个月的第1天,而原始数据中的时间index是每个月的最后一天,因此while current_date in df.index这个指令是无效的,我们对原始数据的时间index加一条:

df.index = df.index + pd.offsets.MonthBegin(-1)

数据处理完成之后,再加一句:

df.index = df.index + pd.offsets.MonthEnd(0)

就可以得到我们想要的结果了

绝对值调整前

绝对值调整后

几点心得

  1. 借助AI编程,需要一点点的编程基础,至少知道AI给的程序是什么意思
  2. 需要很清晰的表述需求,不同的Prompt给的程序有时差别很多,需要尝试不同的Prompt
  3. 文中的几个例子,笔者都自己写过,但是AI给的程序都更简洁,对于一个非科班程序员来说,AI一般来说经验更丰富一些
  4. AI给的代码,会有bug,需要一定的debug能力
  5. 因为AI可以很智能、很聪明的对话,所以借助AI编程,充满了乐趣

 

 

话题:



0

推荐

万钊

万钊

337篇文章 5天前更新

经济学博士

文章