3. Pandas数据预处理

目录

  • 一、删除属性/特征选择
    • 1.1 删除某几列无用的属性、特征
    • 1.2 选择,保留某些特定属性
    • 1.3 更改特征,属性列的顺序
    • 1.4 删除只有一个值的属性
  • 二、缺失值处理
    • 2.1 只要有缺失值null就删除该行样本
    • 2.2 样本中有x个以上的缺失值才删除该行样本
    • 2.3 样本种所有数据都缺失才删除该行样本
    • 2.4 使用属性列的均值来填充缺失值
    • 2.5 使用特定值来填充缺失值
    • 2.6 使用缺失值的前一个/后一个值代替NaN
    • 2.7 传入字典,对不同的列(属性)填充不同的值
    • 2.8 用groupby定位特定的样本群,求统计量后填充缺失值
    • 2.9 拉格朗日插值法
    • 2.10 找到属性值缺失x%的才删除
  • 三、样本/数据选择
    • 3.1 根据某个特定的属性值来选择样本
    • 3.1.1 根据属性A==某值,来找到该样本下属性B的值
    • 3.2 获取包含特定字符str的样本
    • 3.3 使用索引index选取数据
    • 3.4 使用label索引选取数据
    • 3.5 通过属性1的特定值来找属性2的统计量
    • 3.6 随机抽取样本
  • 四、删除样本/数据
    • 4.1 根据行索引删除
    • 4.2 删除重复的样本
    • 4.3 按照某个属性的特定值删除样本
    • 4.4 删除属性值过于单调的属性
    • 4.5 删除包含特定字符串的样本
  • 五、数据,属性,索引变换/修改
    • 5.1 One-hot变换,离散值处理
    • 5.1.2 LabelEncoder变换(有顺序的)
    • 5.2 利用map字典,将某列数据转换成别的值
    • 5.3 利用replace进行替换数据值
    • 5.4根据条件更改值
    • 5.5 整列替换
    • 5.6 eval()列之间的数值运算
    • 5.7 pd.cut分割数值型数据并赋值分组
    • 5.8 将某一列设置为索引
    • 5.9 修改属性名/修改列名
    • 5.10 对data进行重新排序
    • 5.11 对数据中的无穷大/小的数替换
  • 六、字符型str数据修改
    • 6.1 清除字符型数据首尾两端指定的字符,默认为空格
    • 6.2 截取(slice)字符串数据的部分字段
    • 6.3 String数据按照指定的字符进行拆分(split)
    • 6.4 多列字符型str数据合并
    • 6.5 将列表名中的空格用下划线替换掉
    • 6.6 总结对Str型数据的变换操作
  • 七、数据合并、新增
    • 7.1 pd.concat() 简单的数据合并
    • 7.2 在数据集的某行节点,插入样本
    • 7.3 列名不完全相同的数据进行合并
    • 7.4 pd.merge()合并
    • 7.5 新增一列属性
    • 7.6 apply新增列
  • 八、Data Split(测试集·训练集分割)
    • 8.1 普通的随机抽取样本形成测试集、训练集
    • 8.2 根据某个属性的category进行分层抽样
  • 九、数据规范化Feature Scaling
    • 9.1 Standardization标准化
    • 9.2 Min-Max Scaling(Normalization)
    • 9.3 Robust Scaler
  • 十、平衡imbalance数据
    • 10.1 SMOTE
    • 10.2 UnderSample
  • 十一、压缩数据、减少内存
    • 11.1查看数据内存消耗情况
    • 11.2 减少内存
  • 十二、时间处理
    • 12.1 按时间排序
    • 12.2 将字符串时间变成datatime
    • 12.3 只保留年月日、年月等等
    • 12.4 将时间列设置为索引
    • 12.5 统计每一天某个属性的总和

一、删除属性/特征选择

1.1 删除某几列无用的属性、特征

#比如删除ID,ID通常是没用的
data.drop(['ID'],inplace=True,axis=1)

1.2 选择,保留某些特定属性

features = ['feature1','feature2','feature3','feature4'...]
data = data[features]  #往里传入的是列表!!
#注意pandas的Dataframe[]里接受的是列表!!,直接输入属性名的时候别忘了两个[[]]

1.3 更改特征,属性列的顺序

order = ['feature3','feature1','feature2'] #原本顺序是 feature1,feature2,feature3
data = data[order]

1.4 删除只有一个值的属性

值没有变化,对机器学习无意义
Drop those features which contain only one unique value

original_column = data.columns
drop_column = []
for col in original_column:
    feature_values = data[col].dropna().unique() # 1.dropna删除缺失值Nan;2.unique看data[col]这个Series中有几种值:返回的是list
    if len(feature_values) ==1:
        drop_column.append(col)
data = data.drop(drop_column, axis=1)
print(drop_column) #打印被删除的列是哪些

二、缺失值处理

缺失值处理通常有三种方法:

  1. 样本就缺失个别数据,删除样本
  2. 某个属性值缺失太多,就删除该属性,
  3. 用某些值填充

2.1 只要有缺失值null就删除该行样本

data.dropna(inplace=True)  

注意此方法,删除了缺失值所在的行,但是索引值(index)没有重新排序

2.2 样本中有x个以上的缺失值才删除该行样本

data.dropna(axis=0,thresh=8,inplace=True) #样本中至少8个值是非缺失的才保留(总共10个属性)

2.3 样本种所有数据都缺失才删除该行样本

data.dropna(inplace=True, how = 'all')

2.4 使用属性列的均值来填充缺失值

data['Attribute_name'].fillna(data['Attribute_name'].mean(),inplace=True)

2.5 使用特定值来填充缺失值

fill_value = xxxxx
data['Attribute_name'].fillna(fill_value,inplace=True)

2.6 使用缺失值的前一个/后一个值代替NaN

data.fillna(method='pad') #用前一个值替代NaN
data.fillna(method='bfill') #用后一个值替代NaN

2.7 传入字典,对不同的列(属性)填充不同的值

data.fillna({"Attribute_name1":fill_value1,"Attribute_name2":fill_value2...})
#一般不大用,多使用几次fillna填充缺失值,比一次性用字典填充好一些

2.8 用groupby定位特定的样本群,求统计量后填充缺失值

数据中Age缺失的有点多,思想是:将那些与缺失Age样本具有同样Sex和Pclass的群体样本的Age中位数来填充,比如说有个样本缺失Age,它的Sex=female,Pclass=1;那么groupby找到对应的一群样本,求这群样本的Age中位数然后填充缺失值

data['Age'] = data.groupby(['Sex', 'Pclass'])['Age'].apply(lambda x: x.fillna(x.median()))

2.9 拉格朗日插值法

xxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxx

2.10 找到属性值缺失x%的才删除

null_cols = [col for col in data.columns if data[col].isnull().sum() / data.shape[0] > 0.9] # 一个属性中NaN缺失值的个数/样本总数=缺失比率>0.9

三、样本/数据选择

3.1 根据某个特定的属性值来选择样本

推荐使用query

request_data = data.query("feature1 <= num_value1 & feature2== 'str_value2'")
chosen_samples = data[data[attirbute_name] == specific_value]

比较运算法==,<,>,!=…

chosen_samples = data.loc[data['feature_name']=='particular_value']
chosen_samples = data[data.attirbute_name.between(start,end)]

选择某个属性为空的样本(可能用来填充)

null_data = data[data[attirbute_name].isnull()]

逻辑运算

data = data[(condition1)&(condition2)]    and / or / not 

3.1.1 根据属性A==某值,来找到该样本下属性B的值

举例:找到姓名为刘星的样本,他的数学成绩为多少
3. Pandas数据预处理_第1张图片

df.query("姓名=='刘星'")['数学'].values[0]

3.2 获取包含特定字符str的样本

data = data[data[attirbute_name].str.contains("special_words",na=False)]

3.3 使用索引index选取数据

data1 = data.iloc[x,y]  #选取第x+1行,第y+1列
data2 = data.iloc[[x1,x2],:] # 选取第x1+1和第x2+1行,所有列
data3 = data.iloc[x1:x2,:]  #选取第x1+1行 到 x2+1行的所有数据,所有列
series4 = data.iloc[:,y]  #选取数据的第y+1列的值,返回的是Series
series5 = data.iloc[x,:]  #选取数据的第x+1行的值,返回的是Series

3.4 使用label索引选取数据

使用loc时,数据的索引必定是人为指定的label索引,而不是默认的0开始的数字索引

df = data.loc[label_value_x:label_value_y, ] 获取 x行到y行之间的所有样本
df = data.loc[:,attribute_name] #选取attribute_name该列的所有数据

3.5 通过属性1的特定值来找属性2的统计量

df.loc[df['sex'] == 'male', 'Age'].mean()

3.6 随机抽取样本

samples = DataFrame.sample(n,frac,replace,random_state,axis)

n:要抽取的样本数量
frac:抽取的比例
replace:是否有放回,True为放回抽样,默认False
axis 【0,1】控制抽取行(0),还是列(1)

random_factor = numpy.random.randint(start,end,num)  
#start,end是要抽取得范围的索引;num是要抽取的个数
samples = data.loc[random_factor,:]    #也可以直接写成data.loc[random_factor]

四、删除样本/数据

4.1 根据行索引删除

data = data.drop(2)     #删除索引是2的那一行样本

4.2 删除重复的样本

data.drop_duplicates(subset=None, keep='first', inplace=False)  
  • subset:传入的是列名列表[“column_name1”,“column_name2”], 表示几个列合在一起考虑是否有重复值:例如: subset指定[‘sex’,‘id’,‘age’]如果有多个样本中:ID相同,Sex相同,Age相同,才删除重复样本
  • keep:默认是first表示除了第一个出现的值,其他的重复的样本都删除;还可选’last’
    或keep = False:表示所有的重复样本都删除
  • inplace 控制是否就地修改

4.3 按照某个属性的特定值删除样本

data = data[data.attirbute_name != specific_value]

例子

data = data [(data.军训!="缺考")&(data.体育!="作弊")]   #删除数据中军训是缺考,体育是作弊的样本

4.4 删除属性值过于单调的属性

逐列的寻找,看哪些列的属性值分布太过单一,比如说记录分数score属性的列,90%以上都是B,那么这一列就没什么用处,太单调了

most_value_col = [col for col in train_data.columns if train_data[col].value_counts(dropna=False, normalize=True).values[0] > 0.9]

4.5 删除包含特定字符串的样本

data = data[~data['comment'].str.contains('xxx')]

五、数据,属性,索引变换/修改

5.1 One-hot变换,离散值处理

先筛选出dtypes是’object’的属性,返回的是复制的Dataframe

obj_df = df.select_dtypes(include=['object']).copy()
pd.get_dummies(obj_df, columns=["col_1", "col_2"...], prefix=["name1", "name2"])

columns:控制哪些属性进行one-hot变换;可以不传,全用obj_df的属性进行变换
prefix:控制新生成的属性的前缀

5.1.2 LabelEncoder变换(有顺序的)

from sklearn.preprocessing import LabelEncoder

obj_df = train_data.select_dtypes(include=['object']).copy()
categorical_cols = obj_df.columns.tolist()

for col in categorical_cols:
    if col in train_data.columns:
        le = LabelEncoder()
        le.fit(list(train_data[col].astype(str).values) + list(test_data[col].astype(str).values))
        train_data[col] = le.transform(list(train_data[col].astype(str).values))
        test_data[col] = le.transform(list(test_data[col].astype(str).values))

因为sklearn的LabelEncoder只能一列一列转换,就需要用到apply对所有目标列进行转换

x=df.apply(LabelEncoder().fit_transform)

5.2 利用map字典,将某列数据转换成别的值

3. Pandas数据预处理_第2张图片

dict = {'中国':'China','日本':'Japan','韩国':'Korea'......}
data['国家'] = data['国家'].map(dict)

tips: 一开始找到的字典是英中对照的{‘China’: ‘中国’, ‘Japan’: ‘日本’, ‘Korea’: ‘韩国’…}
要先进行key,value对换

dict = {'China': '中国', 'Japan': '日本', 'Korea': '韩国'......}
dict = {x:y for y,x in dict.items()}

5.3 利用replace进行替换数据值

相当于word中的(ctrl+h)替换操作

data.replace("value_A","value_B")  #用B替换A  也可以传入{"value_A":"value_B"}
data['..'] = data[["atrribute1","atrribute2"...]].replace("value_A","value_B")  #inplace=True 就地修改

多列同时替换, 用value_new替换属性1的value1值和属性2的value2值

data = data.replace({"attribute_name_1":"value1","attribute_name_2":"value2"},'value_new')

多值同时替换


data.replace(['a','b','c'...],['A','B','C'...]) #A替换a,B替换b...
data.replace({'a':'A','b':'B','c':'C'...})
data.replace({'a','b','c'...},{'A','B','C'...})

5.4根据条件更改值

data.loc[data['feature_name'] =><!= condition,'feature_name'] = 'new_value'

3. Pandas数据预处理_第3张图片
例如:将reading score<50的更改成F

data.loc[data['reading score'] < 50, 'reading score'] = 'F'

条件逻辑运算符:| 是or,&是and,~是not
https://blog.csdn.net/weixin_42167712/article/details/100060095#16__243

5.5 整列替换

data["attribute_name"] = new_value #new_value 是列表或者Series序列或一个特殊值

5.6 eval()列之间的数值运算

result = pd.eval('df1+df2/df3.....') #eval处理的是字符串   支持&与,|或运算符
#传入eval的字符串里也可以使用属性索引df.iloc[2],也支持列间运算df.feature1 +df.feature2

注意好像eval中不能用data[‘feature’],只能用属性data.feature的形式
或者可以:

resut = data.eval('feature1 + feature2')

例:

pd.eval("(data.reading_score + data.writing_score)/2")

data.eval("(reading_score + writing_score)/2")

也可利用eval()将计算结果作为新增列,如下会新增一列feature4

data.eval('feature4 = (feature1+feature2)/feature3',inplace = True)

eval()还可使用局部变量进行计算

local_mean = data['feature'].mean()
result = data.eval('feature2 +@local_mean')

5.7 pd.cut分割数值型数据并赋值分组

例如将成绩分成A、B、C。。

bins = [min(df["attribute_name"]),60,70,80,max(df["attribute_name"])+1]
level = ["不及格","及格","良好","优秀"]
result =pd.cut(df["attribute_name"],bins,right=False,labels=level)
df["result"] = result

5.8 将某一列设置为索引

指定某列为索引,以便于其他数据进行操作

data = data.set_index("attribute_name")  #指定一列作为DataFrame的索引

可传入drop=False,保留被作为索引的列 ; append=True:保留原来的索引,并增加新的索引列

5.9 修改属性名/修改列名

少量修改个别属性的名字

data.rename(columns={'old name':'new name','old name2':'new name2'},inplace=True)

大量修改属性名

new_column_name = ['col_1','col_2','col_3'....]
data.columns = new_column_name

5.10 对data进行重新排序

data.sort_index()  #按照默认索引index升序排列,降序:往里传入ascending=False
data.sort_index(by="attribute_name")  #按某列属性的值的大小进行排列,也可传入列表,进行多列排列
data.sort_index(axis=1)  #根据列名的字母顺序,对列进行排列
data.reset_index() 

5.11 对数据中的无穷大/小的数替换

将数据集中出现的无穷大和无穷小替换成缺失值
np.inf : 是无穷大的意思

def clean_inf_nan(df):
    return df.replace([np.inf, -np.inf], np.nan)

六、字符型str数据修改

6.1 清除字符型数据首尾两端指定的字符,默认为空格

data["attribute_name"].str.strip()  #删除首尾空格
data["attribute_name"].str.rstrip() #lstrip()
data["attribute_name"].str.strip("s") #删除首尾的s字符

6.2 截取(slice)字符串数据的部分字段

例:截取手机号各个位数,前三位品牌(186联通),中四位表示地区(0315太原),后四位才是号码

data["电话"] =data["电话"].astype(str) #数字转字符串
first_three = data["电话"].str.slice(0,3)

6.3 String数据按照指定的字符进行拆分(split)

data["attribute_name"].str.strip()  #删除首尾空格
newDF = data["attribute_name"].str.split("sep",n,expand=False)
#sep表示用于分割字符串的分隔符 比如空格 点 斜杠 .\
#n表示分割后新增的列数
#expand为True返回DataFrame,默认为False返回Series
#分割后生成的列,用newDF.columns = [“attribute_name1”,”attribute_name2”…]重命名后再整合回去

6.4 多列字符型str数据合并

例如:姓 + 名 → 姓名

data["xing_ming"] = data["xing"]+data["ming"]

6.5 将列表名中的空格用下划线替换掉

data.columns = data.columns.str.replace(' ','_')

6.6 总结对Str型数据的变换操作

#如果Dataframe里某一列数据是string类型的,通过str属性的方法来操作

data['str_feature'].str.method()  # method() = strip/split/upper/lower.....

七、数据合并、新增

7.1 pd.concat() 简单的数据合并

pd.concat([df1,df2],axis=0)  #如果df1,df2列名相同;简单的将df2添加到df1的下方
new_data = pd.concat([df1,df2],axis=1) #将df2按列添加,添加到df1的右边
data = pd.concat([data1,data2],ignore_index=True) #合并数据1和2,并新建一个整数索引

7.2 在数据集的某行节点,插入样本

往data1里面插入data2,插入节点在x+1处

new_data = pd.concat([ data1.loc[:x],data2,data1.loc[x+1:] ],ignore_index=True)  

7.3 列名不完全相同的数据进行合并

new_data = pd.concat([df1,df2], join='outer') #默认join参数'outer'取并集;'inner'是取交集
new_data = pd.concat([df1,df2], join_axes=[df1.columns])   #指定按照df1的列来合并
new_data = pd.concat([df1,df2], join_axes=[specific_column_name_list]) #指定合并后保留的列

7.4 pd.merge()合并

当两个数据集具有相同名字的属性时

merge_data = pd.merge(df1,df2,on='feature')

本文链接:https://blog.csdn.net/brucewong0516/article/details/82707492

7.5 新增一列属性

data['new_feature'] = series_values

7.6 apply新增列

def valuation_formula(x, y):    
	return x * y * 0.5
df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)	

八、Data Split(测试集·训练集分割)

8.1 普通的随机抽取样本形成测试集、训练集

features_data = data.drop(['Label'],axis=1)
label_data = data[['Label']]

from sklearn.model_selection import train_test_split
# 分割数据
train_x, test_x, train_y, test_y = train_test_split(features_data, label_data, test_size=0.25, random_state=33)

8.2 根据某个属性的category进行分层抽样

按照"category_feature"的层级进行分层抽样

from sklearn.model_selection import StratifiedShuffleSplit
X=
y=
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)  
for train_index, test_index in split.split(data, data["category_feature"]):
    #(1)普通训练分割
    X_train, X_test = X.iloc[train_index], X.iloc[test_index]#训练集对应的值
    y_train, y_test = y.iloc[train_index], y.iloc[test_index]#类别集对应的值
    #(2)配合SMOTE/Under Sample
    data_train,data_test = data.iloc[train_index],data.iloc[test_index]

九、数据规范化Feature Scaling

只能fit训练集,然后用fit好的数据转化训练集和测试集!!!!

9.1 Standardization标准化

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
feature_name_list =['col1','col2','col3'...]  #如果是对全部数据进行转换就不需要这个属性列表
data[feature_name_list] = scaler.fit_transform(data[feature_name_list])
#X_train = scaler.fit_transform(X_train)
#X_test = scaler.transform(X_test)
print(scaler.mean_) #返回各列的平均值
print(scaler.scale_) #返回各列的标准差

注意传入的是np.array对象

9.2 Min-Max Scaling(Normalization)

from sklearn.preprocessing import MinMaxScaler
#创建 Min_Max变换
feature_names_list = ['col1','col2','col3'...] 
minmax = MinMaxScaler()
data[feature_names_list] = minmax.fit_transform(data[feature_names_list])

9.3 Robust Scaler

Robust Scaler 变换能减少outliers的影响

from sklearn.preprocessing import  RobustScaler
rob_scaler = RobustScaler()
data[feature_names_list] = rob_scaler.fit_transform(data[feature_names_list])

十、平衡imbalance数据

10.1 SMOTE

from imblearn.over_sampling import SMOTE,ADASYN
features_data,label_data = SMOTE().fit_resample(features_data,np.ravel(label_data))
#经过SMOTE变化后得到的是array数据,需要再加上列名
label_data = pd.DataFrame({"ACTIVITY":label_data})
features_data = pd.DataFrame(features_data,columns=['TIME', 'SL', 'EEG', 'BP', 'HR', 'CIRCLUATION'])

10.2 UnderSample

selected_data = data[data["Class"]==0].sample(n=700) #从class=0的样本中抽取700个样本
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=0)
X_resampled, y_resampled = rus.fit_sample(X, y)

通常data balance 步骤会在数据分割之后,对data_train进行undersample

label_false = data_train[data_train["Label"]=='False'].sample(n=500)
label_true = data_train[data_train["Label"]=='True']
data_undersampled = pd.concat([label_false,label_true]

例:

# undersample 抽取data中所有的fraud 样本400多个,然后在剩下的class=0的样本中sample相等数量的样本就行
fraud_data = data[data["Class"]==1]   # fraud_data dataframe
number_records_fraud = len(fraud_data) # how many fraud samples:492
not_fraud_data = data[data["Class"]==0].sample(n=number_records_fraud)   
training_data_1 = pd.concat([fraud_data,not_fraud_data])

sample(n=?)中传入用len()测量的fraud数据的个数

十一、压缩数据、减少内存

11.1查看数据内存消耗情况

data.info(memory_usage='deep')

11.2 减少内存

def reduce_mem_usage(df, verbose=True):
    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
    start_mem = df.memory_usage().sum() / 1024**2    
    for col in df.columns:
        col_type = df[col].dtypes
        if col_type in numerics:
            c_min = df[col].min()
            c_max = df[col].max()
            if str(col_type)[:3] == 'int':
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)  
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                    df[col] = df[col].astype(np.float32)
                else:
                    df[col] = df[col].astype(np.float64)    
    end_mem = df.memory_usage().sum() / 1024**2
    if verbose: print('Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction)'.format(end_mem, 100 * (start_mem - end_mem) / start_mem))
    return df
data_reduced = reduce_mem_usage(data) #调用构造的方法

十二、时间处理

12.1 按时间排序

从低到高排序

data.sort_values(by="Time" , ascending=True)

12.2 将字符串时间变成datatime

data['Date_Time'] = pd.to_datetime(data['Str_Time'], format='%Y-%m-%d %H:%M:%S')

12.3 只保留年月日、年月等等

from datetime import datetime
data['ym']=data['Date_Time']
data['ym'] =data['ym'].apply(lambda x:datetime.strftime(x,'%Y-%m'))

12.4 将时间列设置为索引

df = df.set_index('Date_Time')

12.5 统计每一天某个属性的总和

统计每天angry的评论多少个

df["angry"].resample('D', how='sum')

你可能感兴趣的:(特征工程)