自定义函数和类实现数据清洗自动化
在数据处理过程中,我们经常需要对数据进行清洗、检查异常值、聚合数据等操作。为了提高代码的复用性和效率,我们可以定义一些自定义函数和类来实现这些功能。本文将详细介绍如何创建和使用这些函数和类,以及它们在实际数据处理中的应用。
1. 检查变量分布和识别异常值
在处理数据时,了解变量的分布情况以及识别异常值是非常重要的。我们可以通过创建自定义函数来完成这些任务。
1.1 导入必要的库并加载数据
首先,我们需要导入一些必要的库,并加载相关的数据。以下是具体的代码:
import pandas as pd
import os
import sys
import pprint
nls97 = pd.read_csv("data/nls97f.csv")
nls97.set_index('personid', inplace=True)
covidtotals = pd.read_csv("data/covidtotals720.csv")
1.2 创建函数显示分布的重要属性
我们创建一个名为
getdistprops
的函数,该函数接受一个序列作为输入,并返回一个包含分布的中心趋势、形状和离散程度等指标的字典。以下是函数的代码:
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as scistat
import math
def getdistprops(seriestotest):
out = {}
normstat, normpvalue = scistat.shapiro(seriestotest)
if (not math.isnan(normstat)):
out['normstat'] = normstat
if (normpvalue>=0.05):
out['normpvalue'] = str(round(normpvalue, 2)) + ": Accept Normal"
elif (normpvalue<0.05):
out['normpvalue'] = str(round(normpvalue, 2)) + ": Reject Normal"
out['mean'] = seriestotest.mean()
out['median'] = seriestotest.median()
out['std'] = seriestotest.std()
out['kurtosis'] = seriestotest.kurtosis()
out['skew'] = seriestotest.skew()
out['count'] = seriestotest.count()
return out
将上述函数保存到
helperfunctions
子文件夹下的
outliers.py
文件中。
1.3 调用函数检查变量分布
我们将
covidtotals
数据集中的
total_cases_pm
序列传递给
getdistprops
函数,以检查该变量的分布情况。以下是调用代码:
import outliers as ol
dist = ol.getdistprops(covidtotals.total_cases_pm)
pprint.pprint(dist)
输出结果如下:
{'count': 209,
'kurtosis': 26.137524276840452,
'mean': 2297.0221435406693,
'median': 868.866,
'normpvalue': '0.0: Reject Normal',
'normstat': 0.5617035627365112,
'skew': 4.284484653881833,
'std': 4039.840202653782}
从输出结果可以看出,
total_cases_pm
变量的分布具有显著的正偏态和较厚的尾部,这与正态分布不同。
1.4 创建函数列出数据框中的异常值
我们创建一个名为
getoutliers
的函数,该函数用于列出数据框中的异常值。以下是函数的代码:
def getoutliers(dfin, sumvars, othervars):
dfin = dfin[sumvars + othervars]
dfout = pd.DataFrame(columns=dfin.columns, data=None)
dfsums = dfin[sumvars]
for col in dfsums.columns:
thirdq, firstq = dfsums[col].quantile(0.75), dfsums[col].quantile(0.25)
interquartilerange = 1.5*(thirdq-firstq)
outlierhigh, outlierlow = interquartilerange+thirdq, firstq-interquartilerange
df = dfin.loc[(dfin[col]>outlierhigh) | (dfin[col]<outlierlow)]
df = df.assign(varname = col, threshlow = outlierlow, threshhigh = outlierhigh)
dfout = pd.concat([dfout, df])
return dfout
1.5 调用函数列出异常值
我们将
nls97
数据框传递给
getoutliers
函数,并指定要检查的列和要包含在结果中的列。以下是调用代码:
sumvars = ['satmath','wageincome']
othervars = ['originalid','highestdegree','gender','maritalstatus']
outliers = ol.getoutliers(nls97, sumvars, othervars)
outliers.varname.value_counts(sort=False)
outliers.loc[outliers.varname=='satmath', othervars + sumvars]
outliers.to_excel("views/nlsoutliers.xlsx")
输出结果显示了每个变量的异常值数量,以及
satmath
变量的异常值。
1.6 创建函数生成直方图和箱线图
我们创建一个名为
makeplot
的函数,该函数用于生成直方图和箱线图。以下是函数的代码:
def makeplot(seriestoplot, title, xlabel, plottype="hist"):
if (plottype=="hist"):
plt.hist(seriestoplot)
plt.axvline(seriestoplot.mean(), color='red', linestyle='dashed', linewidth=1)
plt.xlabel(xlabel)
plt.ylabel("Frequency")
elif (plottype=="box"):
plt.boxplot(seriestoplot.dropna(), labels=[xlabel])
plt.title(title)
plt.show()
1.7 调用函数生成直方图和箱线图
我们将
nls97
数据框中的
satmath
列传递给
makeplot
函数,分别生成直方图和箱线图。以下是调用代码:
ol.makeplot(nls97.satmath, "Histogram of SAT Math", "SAT Math")
ol.makeplot(nls97.satmath, "Boxplot of SAT Math", "SAT Math", "box")
2. 数据聚合和合并
在数据处理过程中,我们经常需要对数据进行聚合和合并操作。我们可以通过创建自定义函数来完成这些任务。
2.1 导入必要的库
首先,我们需要导入一些必要的库。以下是具体的代码:
import pandas as pd
import os
import sys
2.2 创建函数按组和时间段聚合值
我们创建一个名为
adjmeans
的函数,该函数用于按组和时间段聚合值。以下是函数的代码:
def adjmeans(df, byvar, var, period, changeexclude=None, excludetype=None):
df = df.sort_values([byvar, period])
df = df.dropna(subset=[var])
prevbyvar = 'ZZZ'
prevvarvalue = 0
rowlist = []
varvalues = df[[byvar, var]].values
if (excludetype=="ratio" and changeexclude is not None):
changeexclude = df[var].mean()*changeexclude
for j in range(len(varvalues)):
byvar = varvalues[j][0]
varvalue = varvalues[j][1]
if (prevbyvar!=byvar):
if (prevbyvar!='ZZZ'):
rowlist.append({'byvar':prevbyvar, 'avgvar':varsum/byvarcnt, 'sumvar':varsum, 'byvarcnt':byvarcnt})
varsum = 0
byvarcnt = 0
prevbyvar = byvar
if ((changeexclude is None) or (0 <= abs(varvalue-prevvarvalue) <= changeexclude) or (byvarcnt==0)):
varsum += varvalue
byvarcnt += 1
prevvarvalue = varvalue
rowlist.append({'byvar':prevbyvar, 'avgvar':varsum/byvarcnt, 'sumvar':varsum, 'byvarcnt':byvarcnt})
return pd.DataFrame(rowlist)
将上述函数保存到
helperfunctions
子文件夹下的
combineagg.py
文件中。
2.3 导入模块并加载数据
我们导入
combineagg
模块,并加载相关的数据。以下是具体的代码:
sys.path.append(os.getcwd() + "/helperfunctions")
import combineagg as ca
coviddaily = pd.read_csv("data/coviddaily720.csv")
ltbrazil = pd.read_csv("data/ltbrazil.csv")
countries = pd.read_csv("data/ltcountries.csv")
locations = pd.read_csv("data/ltlocations.csv")
2.4 调用函数按组和时间段聚合值
我们将
coviddaily
数据框传递给
adjmeans
函数,按
location
分组并按
casedate
时间段聚合
new_cases
列的值。以下是调用代码:
ca.adjmeans(coviddaily, 'location', 'new_cases', 'casedate')
输出结果显示了每个国家的
new_cases
列的平均值、总和和计数。
2.5 再次调用函数并排除异常值
我们再次调用
adjmeans
函数,并指定排除
new_cases
列中相邻两天变化超过 150 的值。以下是调用代码:
ca.adjmeans(coviddaily, 'location', 'new_cases', 'casedate', 150)
输出结果显示,排除异常值后,一些国家的计数有所减少。
2.6 创建函数检查合并列的值
我们创建一个名为
checkmerge
的函数,该函数用于检查两个数据框中合并列的值。以下是函数的代码:
def checkmerge(dfleft, dfright, mergebyleft, mergebyright):
dfleft['inleft'] = "Y"
dfright['inright'] = "Y"
dfboth = pd.merge(dfleft[[mergebyleft,'inleft']], dfright[[mergebyright,'inright']], left_on=[mergebyleft], right_on=[mergebyright], how="outer")
dfboth.fillna('N', inplace=True)
print(pd.crosstab(dfboth.inleft, dfboth.inright))
print(dfboth.loc[(dfboth.inleft=='N') | (dfboth.inright=='N')].head(20))
2.7 调用函数检查合并列的值
我们将
countries
和
locations
数据框传递给
checkmerge
函数,检查
countryid
列的值。以下是调用代码:
ca.checkmerge(countries.copy(), locations.copy(), "countryid", "countryid")
输出结果显示了两个数据框中
countryid
列的值的匹配情况。
2.8 创建函数合并文件夹中的所有 CSV 文件
我们创建一个名为
addfiles
的函数,该函数用于合并文件夹中的所有 CSV 文件。以下是函数的代码:
def addfiles(directory):
dfout = pd.DataFrame()
columnsmatched = True
for filename in os.listdir(directory):
if filename.endswith(".csv"):
fileloc = os.path.join(directory, filename)
with open(fileloc) as f:
dfnew = pd.read_csv(fileloc)
print(filename + " has " + str(dfnew.shape[0]) + " rows.")
dfout = pd.concat([dfout, dfnew])
columndiff = dfout.columns.symmetric_difference(dfnew.columns)
if (not columndiff.empty):
print("", "Different column names for:", filename, columndiff, "", sep="\n")
columnsmatched = False
print("Columns Matched:", columnsmatched)
return dfout
2.9 调用函数合并文件夹中的所有 CSV 文件
我们将
data/ltcountry
文件夹传递给
addfiles
函数,合并该文件夹中的所有 CSV 文件。以下是调用代码:
landtemps = ca.addfiles("data/ltcountry")
landtemps.country.value_counts()
输出结果显示了合并后的数据框中每个国家的行数。
通过以上步骤,我们可以看到如何使用自定义函数和类来实现数据清洗、检查异常值、聚合数据和合并数据等操作。这些函数和类可以提高代码的复用性和效率,使数据处理更加自动化和系统化。
自定义函数和类实现数据清洗自动化
3. 包含更新系列值逻辑的类
在处理特定数据集时,若数据会定期更新但结构相对稳定,且有大量列,使用类可以提高代码的可靠性和可读性。下面我们将创建一个
Respondent
类来处理 NLS 数据。
3.1 导入必要的库
我们需要导入一些必要的库,并将代码存储在
class_cleaning.py
文件中。以下是具体的代码:
import pandas as pd
import os
import sys
import pprint
3.2 创建
Respondent
类
创建
Respondent
类并将其保存到
helperfunctions
子文件夹下的
respondent.py
文件中。该类的
__init__
方法会在实例化对象时自动运行,它接受一个字典作为参数,并将其赋值给实例变量
self.respdict
,同时增加一个计数器
respondentcnt
。以下是类的代码:
import math
import datetime as dt
class Respondent:
respondentcnt = 0
def __init__(self, respdict):
self.respdict = respdict
Respondent.respondentcnt += 1
3.3 添加计算子女数量的方法
为
Respondent
类添加一个
childnum
方法,用于计算受访者的子女总数。该方法通过将居住在家中的子女数量和不在家中的子女数量相加得到结果。以下是方法的代码:
def childnum(self):
return self.respdict['childathome'] + self.respdict['childnotathome']
3.4 添加计算平均工作周数的方法
添加一个
avgweeksworked
方法,用于计算受访者在 20 年调查期间的平均工作周数。该方法使用字典推导式创建一个包含非缺失值的工作周数的字典,然后计算这些值的总和并除以字典的长度。以下是方法的代码:
def avgweeksworked(self):
workdict = {k: v for k, v in self.respdict.items() if k.startswith('weeksworked') and not math.isnan(v)}
nweeks = len(workdict)
if (nweeks > 0):
avgww = sum(workdict.values()) / nweeks
else:
avgww = 0
return avgww
3.5 添加计算指定日期年龄的方法
添加一个
ageby
方法,用于计算受访者在指定日期的年龄。该方法将日期字符串转换为
datetime
对象,然后根据出生年份和月份计算年龄。以下是方法的代码:
def ageby(self, bydatestring):
bydate = dt.datetime.strptime(bydatestring, '%Y%m%d')
birthyear = self.respdict['birthyear']
birthmonth = self.respdict['birthmonth']
age = bydate.year - birthyear
if (bydate.month < birthmonth or (bydate.month == birthmonth and bydate.day < 15)):
age = age - 1
return age
3.6 添加判断是否就读 4 年制大学的方法
添加一个
baenrollment
方法,用于判断受访者是否曾经就读于 4 年制大学。该方法使用字典推导式检查是否有任何大学入学值表明就读于 4 年制大学。以下是方法的代码:
def baenrollment(self):
colenrdict = {k: v for k, v in self.respdict.items() if k.startswith('colenr') and v == "3. 4 - year college"}
if (len(colenrdict) > 0):
return "Y"
else:
return "N"
3.7 导入
Respondent
类
在
class_cleaning.py
文件中导入
Respondent
类。以下是导入代码:
sys.path.append(os.getcwd() + "/helperfunctions")
import respondent as rp
3.8 加载 NLS 数据并创建字典列表
加载 NLS 数据,并使用
to_dict
方法将其转换为字典列表。以下是具体的代码:
nls97 = pd.read_csv("data/nls97f.csv")
nls97list = nls97.to_dict('records')
nls97.shape
len(nls97list)
pprint.pprint(nls97list[0:1])
输出结果如下:
(8984, 89)
8984
[{'birthmonth': 5,
'birthyear': 1980,
'childathome': 4.0,
'childnotathome': 0.0,
'colenrfeb00': '1. Not enrolled',
'colenrfeb01': '1. Not enrolled',
...
'weeksworked16': 48.0,
'weeksworked17': 48.0}]
3.9 循环创建
Respondent
实例
遍历字典列表,为每个字典创建一个
Respondent
实例,并使用实例方法获取所需的值,将这些值存储在一个新的字典中,然后将新字典添加到
analysislist
中。以下是具体的代码:
analysislist = []
for respdict in nls97list:
resp = rp.Respondent(respdict)
newdict = dict(originalid=respdict['originalid'],
childnum=resp.childnum(),
avgweeksworked=resp.avgweeksworked(),
age=resp.ageby('20201015'),
baenrollment=resp.baenrollment())
analysislist.append(newdict)
3.10 将字典列表转换为 DataFrame
将
analysislist
传递给
pandas
的
DataFrame
方法,创建一个新的数据框。首先,检查
analysislist
中的项目数量和创建的实例数量。以下是具体的代码:
len(analysislist)
resp.respondentcnt
pprint.pprint(analysislist[0:2])
输出结果如下:
8984
8984
[{'age': 40,
'avgweeksworked': 49.05555555555556,
'baenrollment': 'Y',
'childnum': 4.0,
'originalid': 8245},
...]
总结
通过以上内容,我们展示了如何使用自定义函数和类来实现数据清洗、检查异常值、聚合数据、合并数据以及更新系列值等操作。下面是一个简单的操作流程总结:
| 操作类型 | 操作步骤 |
|---|---|
| 检查变量分布和识别异常值 |
1. 导入必要的库并加载数据
2. 创建函数显示分布的重要属性 3. 调用函数检查变量分布 4. 创建函数列出数据框中的异常值 5. 调用函数列出异常值 6. 创建函数生成直方图和箱线图 7. 调用函数生成直方图和箱线图 |
| 数据聚合和合并 |
1. 导入必要的库
2. 创建函数按组和时间段聚合值 3. 导入模块并加载数据 4. 调用函数按组和时间段聚合值 5. 再次调用函数并排除异常值 6. 创建函数检查合并列的值 7. 调用函数检查合并列的值 8. 创建函数合并文件夹中的所有 CSV 文件 9. 调用函数合并文件夹中的所有 CSV 文件 |
| 包含更新系列值逻辑的类 |
1. 导入必要的库
2. 创建
Respondent
类
3. 添加计算子女数量的方法 4. 添加计算平均工作周数的方法 5. 添加计算指定日期年龄的方法 6. 添加判断是否就读 4 年制大学的方法 7. 导入
Respondent
类
8. 加载 NLS 数据并创建字典列表 9. 循环创建
Respondent
实例
10. 将字典列表转换为 DataFrame |
以下是一个 mermaid 流程图,展示了整个数据处理的主要流程:
graph LR
A[数据加载] --> B[检查变量分布和异常值]
B --> C[数据聚合和合并]
C --> D[使用类更新系列值]
这些自定义函数和类可以提高代码的复用性和效率,使数据处理更加自动化和系统化。在实际应用中,我们可以根据具体需求对这些函数和类进行扩展和修改。
超级会员免费看
1729

被折叠的 条评论
为什么被折叠?



