Pandas实现数据的合并concat

使用场景:

批量合并相同格式的Excel、给DataFrame添加行、给DataFrame添加列

一句话说明concat语法:

  • 使用某种合并方式(inner/outer)
  • 沿着某个轴向(axis=0/1)
  • 把多个Pandas对象(DataFrame/Series)合并成一个。

concat语法:pandas.concat(objs, axis=0, join=’outer’, ignore_index=False)

  • objs:一个列表,内容可以是DataFrame或者Series,可以混合
  • axis:默认是0代表按行合并,如果等于1代表按列合并
  • join:合并的时候索引的对齐方式,默认是outer join,也可以是inner join
  • ignore_index:是否忽略掉原来的数据索引

append语法:DataFrame.append(other, ignore_index=False)

append只有按行合并,没有按列合并,相当于concat按行的简写形式
* other:单个dataframe、series、dict,或者列表
* ignore_index:是否忽略掉原来的数据索引

参考文档:

  • pandas.concat的api文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html
  • pandas.concat的教程:https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html
  • pandas.append的api文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.append.html
import pandas as pd

import warnings
warnings.filterwarnings('ignore')

一、使用pandas.concat合并数据

df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
                    'B': ['B0', 'B1', 'B2', 'B3'],
                    'C': ['C0', 'C1', 'C2', 'C3'],
                    'D': ['D0', 'D1', 'D2', 'D3'],
                    'E': ['E0', 'E1', 'E2', 'E3']
                   })
df1
ABCDE
0A0B0C0D0E0
1A1B1C1D1E1
2A2B2C2D2E2
3A3B3C3D3E3
df2 = pd.DataFrame({ 'A': ['A4', 'A5', 'A6', 'A7'],
                     'B': ['B4', 'B5', 'B6', 'B7'],
                     'C': ['C4', 'C5', 'C6', 'C7'],
                     'D': ['D4', 'D5', 'D6', 'D7'],
                     'F': ['F4', 'F5', 'F6', 'F7']
                   })
df2
ABCDF
0A4B4C4D4F4
1A5B5C5D5F5
2A6B6C6D6F6
3A7B7C7D7F7

1、默认的concat,参数为axis=0、join=outer、ignore_index=False

pd.concat([df1,df2])
ABCDEF
0A0B0C0D0E0NaN
1A1B1C1D1E1NaN
2A2B2C2D2E2NaN
3A3B3C3D3E3NaN
0A4B4C4D4NaNF4
1A5B5C5D5NaNF5
2A6B6C6D6NaNF6
3A7B7C7D7NaNF7

2、使用ignore_index=True可以忽略原来的索引

pd.concat([df1,df2], ignore_index=True)
ABCDEF
0A0B0C0D0E0NaN
1A1B1C1D1E1NaN
2A2B2C2D2E2NaN
3A3B3C3D3E3NaN
4A4B4C4D4NaNF4
5A5B5C5D5NaNF5
6A6B6C6D6NaNF6
7A7B7C7D7NaNF7

3、使用join=inner过滤掉不匹配的列

pd.concat([df1,df2], ignore_index=True, join="inner")
ABCD
0A0B0C0D0
1A1B1C1D1
2A2B2C2D2
3A3B3C3D3
4A4B4C4D4
5A5B5C5D5
6A6B6C6D6
7A7B7C7D7

4、使用axis=1相当于添加新列

df1
ABCDE
0A0B0C0D0E0
1A1B1C1D1E1
2A2B2C2D2E2
3A3B3C3D3E3

A:添加一列Series

s1 = pd.Series(list(range(4)), name="F")
pd.concat([df1,s1], axis=1)
ABCDEF
0A0B0C0D0E00
1A1B1C1D1E11
2A2B2C2D2E22
3A3B3C3D3E33

B:添加多列Series

s2 = df1.apply(lambda x:x["A"]+"_GG", axis=1)
s2
0    A0_GG
1    A1_GG
2    A2_GG
3    A3_GG
dtype: object
s2.name="G"
pd.concat([df1,s1,s2], axis=1)
ABCDEFG
0A0B0C0D0E00A0_GG
1A1B1C1D1E11A1_GG
2A2B2C2D2E22A2_GG
3A3B3C3D3E33A3_GG
# 列表可以只有Series
pd.concat([s1,s2], axis=1)
FG
00A0_GG
11A1_GG
22A2_GG
33A3_GG
# 列表是可以混合顺序的
pd.concat([s1,df1,s2], axis=1)
FABCDEG
00A0B0C0D0E0A0_GG
11A1B1C1D1E1A1_GG
22A2B2C2D2E2A2_GG
33A3B3C3D3E3A3_GG

二、使用DataFrame.append按行合并数据

df1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
df1
AB
012
134
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
df2
AB
056
178

1、给1个dataframe添加另一个dataframe

df1.append(df2)
AB
012
134
056
178

2、忽略原来的索引ignore_index=True

df1.append(df2, ignore_index=True)
AB
012
134
256
378

3、可以一行一行的给DataFrame添加数据

# 一个空的df
df = pd.DataFrame(columns=['A'])
df
A

A:低性能版本

for i in range(5):
    # 注意这里每次都在复制
    df = df.append({'A': i}, ignore_index=True)
df
A
00
11
22
33
44

B:性能好的版本

# 第一个入参是一个列表,避免了多次复制
pd.concat(
    [pd.DataFrame([i], columns=['A']) for i in range(5)],
    ignore_index=True
)
A
00
11
22
33
44

Pandas的Index索引有什么用途?

把数据存储于普通的column列也能用于数据查询,那使用index有什么好处?

index的用途总结:
1. 更方便的数据查询;
2. 使用index可以获得性能提升;
3. 自动的数据对齐功能;
4. 更多更强大的数据结构支持;

import pandas as pd
df = pd.read_csv("./datas/ml-latest-small/ratings.csv")
df.head()
userIdmovieIdratingtimestamp
0114.0964982703
1134.0964981247
2164.0964982224
31475.0964983815
41505.0964982931
df.count()
userId       100836
movieId      100836
rating       100836
timestamp    100836
dtype: int64

1、使用index查询数据

# drop==False,让索引列还保持在column
df.set_index("userId", inplace=True, drop=False)
df.head()
userIdmovieIdratingtimestamp
userId
1114.0964982703
1134.0964981247
1164.0964982224
11475.0964983815
11505.0964982931
df.index
Int64Index([  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
            ...
            610, 610, 610, 610, 610, 610, 610, 610, 610, 610],
           dtype='int64', name='userId', length=100836)
# 使用index的查询方法
df.loc[500].head(5)
userIdmovieIdratingtimestamp
userId
50050014.01005527755
500500111.01005528017
500500391.01005527926
5005001011.01005527980
5005001044.01005528065
# 使用column的condition查询方法
df.loc[df["userId"] == 500].head()
userIdmovieIdratingtimestamp
userId
50050014.01005527755
500500111.01005528017
500500391.01005527926
5005001011.01005527980
5005001044.01005528065

2. 使用index会提升查询性能

  • 如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1);
  • 如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN);
  • 如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N);

实验1:完全随机的顺序查询

# 将数据随机打散
from sklearn.utils import shuffle
df_shuffle = shuffle(df)
df_shuffle.head()
userIdmovieIdratingtimestamp
userId
16016023401.0985383314
12912911363.51167375403
167167441914.51154718915
5365362763.0832839990
676759522.01501274082
# 索引是否是递增的
df_shuffle.index.is_monotonic_increasing
False
df_shuffle.index.is_unique
False
# 计时,查询id==500数据性能
%timeit df_shuffle.loc[500]
376 µs ± 52.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

实验2:将index排序后的查询

df_sorted = df_shuffle.sort_index()
df_sorted.head()
userIdmovieIdratingtimestamp
userId
1129854.0964983034
1126172.0964982588
1136394.0964982271
1164.0964982224
117334.0964982400
# 索引是否是递增的
df_sorted.index.is_monotonic_increasing
True
df_sorted.index.is_unique
False
%timeit df_sorted.loc[500]
203 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

3. 使用index能自动对齐数据

包括series和dataframe

s1 = pd.Series([1,2,3], index=list("abc"))
s1
a    1
b    2
c    3
dtype: int64
s2 = pd.Series([2,3,4], index=list("bcd"))
s2
b    2
c    3
d    4
dtype: int64
s1+s2
a    NaN
b    4.0
c    6.0
d    NaN
dtype: float64

4. 使用index更多更强大的数据结构支持

很多强大的索引数据结构
* CategoricalIndex,基于分类数据的Index,提升性能;
* MultiIndex,多维索引,用于groupby多维聚合后结果等;
* DatetimeIndex,时间类型索引,强大的日期和时间的方法支持;

机器学习常用数据集大全

UCI Machine Learning Adult Dataset

Business Problem: Classification (a person earns more than 50k or less) Predictor Variable: Label ; Predictors: country, age, education, occupation, marital status etc.

文章:https://towardsdatascience.com/pandas-index-explained-b131beaf6f7b
数据集地址:https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data

Kaggle – Avazu:Click-Through Rate Prediction

Predict whether a mobile ad will be clicked
In online advertising, click-through rate (CTR) is a very important metric for evaluating ad performance. As a result, click prediction systems are essential and widely used for sponsored search and real-time bidding.

Kaggle地址:
https://www.kaggle.com/c/avazu-ctr-prediction/overview

UCI – Adult Data Set $50k

Predict whether income exceeds $50K/yr based on census data. Also known as “Census Income” dataset
https://archive.ics.uci.edu/ml/datasets/Adult

UCI – Iris Data Set

This is perhaps the best known database to be found in the pattern recognition literature. Fisher’s paper is a classic in the field and is referenced frequently to this day
https://archive.ics.uci.edu/ml/datasets/Iris

Kaggle Titanic: Machine Learning from Disaster

use machine learning to create a model that predicts which passengers survived the Titanic shipwreck.

https://www.kaggle.com/c/titanic

一个数据科学家的修炼路径

来自一个视频:

数据科学家的需求层次,从底层往上层依次需要:

  • COLLECT,数据收集
  • MOVE/STORE,数据传输和存储
  • EXPLORE/TRANSOFRM,数据探索、清洗、异常检测过滤等
  • AGGREGATE/LABEL,分析、指标、聚合、特征工程、输出训练数据
  • LEARN/OPTIMIZE,AB测试、试验、简单的机器学习算法
  • AI/DEEP LEARNING,人工智能,深度学习

数据科学家的核心要义:
不需要复杂的算法,只需要你用任何手段解决公司的问题
一切都是为了解决问题

Pandas的axis参数怎么理解?

axis参数非常的让人困惑难以理解,本视频我会用形象化的方式讲解一下这个参数,核心要诀就是axis那个轴会消失!

  • axis=0或者”index”:
    • 如果是单行操作,就指的是某一行
    • 如果是聚合操作,指的是跨行cross rows
  • axis=1或者”columns”:
    • 如果是单列操作,就指的是某一列
    • 如果是聚合操作,指的是跨列cross columns

按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

import pandas as pd
import numpy as np
df = pd.DataFrame(
    np.arange(12).reshape(3,4),
    columns=['A', 'B', 'C', 'D']
)
df
ABCD
00123
14567
2891011

1、单列drop,就是删除某一列

# 代表的就是删除某列
df.drop("A", axis=1)
BCD
0123
1567
291011

2、单行drop,就是删除某一行

df
ABCD
00123
14567
2891011
# 代表的就是删除某行
df.drop(1, axis=0)
ABCD
00123
2891011

3、按axis=0/index执行mean聚合操作

反直觉:输出的不是每行的结果,而是每列的结果

df
ABCD
00123
14567
2891011
# axis=0 or axis=index
df.mean(axis=0)
A    4.0
B    5.0
C    6.0
D    7.0
dtype: float64

指定了按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

4、按axis=1/columns执行mean聚合操作

反直觉:输出的不是每行的结果,而是每列的结果

df
ABCD
00123
14567
2891011
# axis=1 or axis=columns
df.mean(axis=1)
0    1.5
1    5.5
2    9.5
dtype: float64

指定了按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

5、再次举例,加深理解

def get_sum_value(x):
    return x["A"] + x["B"] + x["C"] + x["D"]

df["sum_value"] = df.apply(get_sum_value, axis=1)
df
ABCDsum_value
001236
1456722
289101138

指定了按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动

本文地址:http://www.crazyant.net/2546.html
转载请注明来源

Pandas怎样处理字符串?

前面我们已经使用了字符串的处理函数:
df[“bWendu”].str.replace(“℃”, “”).astype(‘int32’)

Pandas的字符串处理:
1. 使用方法:先获取Series的str属性,然后在属性上调用函数;
2. 只能在字符串列上使用,不能数字列上使用;
3. Dataframe上没有str属性和处理方法
4. Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似;

Series.str字符串方法列表参考文档:
https://pandas.pydata.org/pandas-docs/stable/reference/series.html#string-handling

本节演示内容:
1. 获取Series的str属性,然后使用各种字符串处理函数
2. 使用str的startswith、contains等bool类Series可以做条件查询
3. 需要多次str处理的链式操作
4. 使用正则表达式的处理

0、读取北京2018年天气数据

import pandas as pd
fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)
df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013℃-6℃晴~多云东北风1-2级592
12018-01-022℃-5℃阴~多云东北风1-2级491
22018-01-032℃-5℃多云北风1-2级281
32018-01-040℃-8℃东北风1-2级281
42018-01-053℃-6℃多云~晴西北风1-2级501
df.dtypes
ymd          object
bWendu       object
yWendu       object
tianqi       object
fengxiang    object
fengli       object
aqi           int64
aqiInfo      object
aqiLevel      int64
dtype: object

1、获取Series的str属性,使用各种字符串处理函数

df["bWendu"].str
<pandas.core.strings.StringMethods at 0x1af21871808>
# 字符串替换函数
df["bWendu"].str.replace("℃", "")
0       3
1       2
2       2
3       0
4       3
       ..
360    -5
361    -3
362    -3
363    -2
364    -2
Name: bWendu, Length: 365, dtype: object
# 判断是不是数字
df["bWendu"].str.isnumeric()
0      False
1      False
2      False
3      False
4      False
       ...  
360    False
361    False
362    False
363    False
364    False
Name: bWendu, Length: 365, dtype: bool
df["aqi"].str.len()
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-8-12cdcbdb6f81> in <module>
----> 1 df["aqi"].str.len()


d:\appdata\python37\lib\site-packages\pandas\core\generic.py in __getattr__(self, name)
   5173             or name in self._accessors
   5174         ):
-> 5175             return object.__getattribute__(self, name)
   5176         else:
   5177             if self._info_axis._can_hold_identifiers_and_holds_name(name):


d:\appdata\python37\lib\site-packages\pandas\core\accessor.py in __get__(self, obj, cls)
    173             # we're accessing the attribute of the class, i.e., Dataset.geo
    174             return self._accessor
--> 175         accessor_obj = self._accessor(obj)
    176         # Replace the property with the accessor object. Inspired by:
    177         # http://www.pydanny.com/cached-property.html


d:\appdata\python37\lib\site-packages\pandas\core\strings.py in __init__(self, data)
   1915 
   1916     def __init__(self, data):
-> 1917         self._inferred_dtype = self._validate(data)
   1918         self._is_categorical = is_categorical_dtype(data)
   1919 


d:\appdata\python37\lib\site-packages\pandas\core\strings.py in _validate(data)
   1965 
   1966         if inferred_dtype not in allowed_types:
-> 1967             raise AttributeError("Can only use .str accessor with string " "values!")
   1968         return inferred_dtype
   1969 


AttributeError: Can only use .str accessor with string values!

2、使用str的startswith、contains等得到bool的Series可以做条件查询

condition = df["ymd"].str.startswith("2018-03")
condition
0      False
1      False
2      False
3      False
4      False
       ...  
360    False
361    False
362    False
363    False
364    False
Name: ymd, Length: 365, dtype: bool
df[condition].head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
592018-03-018℃-3℃多云西南风1-2级461
602018-03-029℃-1℃晴~多云北风1-2级952
612018-03-0313℃3℃多云~阴北风1-2级214重度污染5
622018-03-047℃-2℃阴~多云东南风1-2级144轻度污染3
632018-03-058℃-3℃南风1-2级942

3、需要多次str处理的链式操作

怎样提取201803这样的数字月份?
1、先将日期2018-03-31替换成20180331的形式
2、提取月份字符串201803

df["ymd"].str.replace("-", "")
0      20180101
1      20180102
2      20180103
3      20180104
4      20180105
         ...   
360    20181227
361    20181228
362    20181229
363    20181230
364    20181231
Name: ymd, Length: 365, dtype: object
# 每次调用函数,都返回一个新Series
df["ymd"].str.replace("-", "").slice(0, 6)
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-13-ae278fb12255> in <module>
      1 # 每次调用函数,都返回一个新Series
----> 2 df["ymd"].str.replace("-", "").slice(0, 6)


d:\appdata\python37\lib\site-packages\pandas\core\generic.py in __getattr__(self, name)
   5177             if self._info_axis._can_hold_identifiers_and_holds_name(name):
   5178                 return self[name]
-> 5179             return object.__getattribute__(self, name)
   5180 
   5181     def __setattr__(self, name, value):


AttributeError: 'Series' object has no attribute 'slice'
df["ymd"].str.replace("-", "").str.slice(0, 6)
0      201801
1      201801
2      201801
3      201801
4      201801
        ...  
360    201812
361    201812
362    201812
363    201812
364    201812
Name: ymd, Length: 365, dtype: object
# slice就是切片语法,可以直接用
df["ymd"].str.replace("-", "").str[0:6]
0      201801
1      201801
2      201801
3      201801
4      201801
        ...  
360    201812
361    201812
362    201812
363    201812
364    201812
Name: ymd, Length: 365, dtype: object

4. 使用正则表达式的处理

# 添加新列
def get_nianyueri(x):
    year,month,day = x["ymd"].split("-")
    return f"{year}年{month}月{day}日"
df["中文日期"] = df.apply(get_nianyueri, axis=1)
df["中文日期"]
0      2018年01月01日
1      2018年01月02日
2      2018年01月03日
3      2018年01月04日
4      2018年01月05日
          ...     
360    2018年12月27日
361    2018年12月28日
362    2018年12月29日
363    2018年12月30日
364    2018年12月31日
Name: 中文日期, Length: 365, dtype: object

问题:怎样将“2018年12月31日”中的年、月、日三个中文字符去除?

# 方法1:链式replace
df["中文日期"].str.replace("年", "").str.replace("月","").str.replace("日", "")
0      20180101
1      20180102
2      20180103
3      20180104
4      20180105
         ...   
360    20181227
361    20181228
362    20181229
363    20181230
364    20181231
Name: 中文日期, Length: 365, dtype: object

Series.str默认就开启了正则表达式模式

# 方法2:正则表达式替换
df["中文日期"].str.replace("[年月日]", "")
0      20180101
1      20180102
2      20180103
3      20180104
4      20180105
         ...   
360    20181227
361    20181228
362    20181229
363    20181230
364    20181231
Name: 中文日期, Length: 365, dtype: object

Pandas怎样对数据进行排序?

Series的排序:
Series.sort_values(ascending=True, inplace=False)
参数说明:
* ascending:默认为True升序排序,为False降序排序
* inplace:是否修改原始Series

DataFrame的排序:
DataFrame.sort_values(by, ascending=True, inplace=False)
参数说明:
* by:字符串或者List<字符串>,单列排序或者多列排序
* ascending:bool或者List,升序还是降序,如果是list对应by的多列
* inplace:是否修改原始DataFrame

import pandas as pd

0、读取数据

fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)

# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')
df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013-6晴~多云东北风1-2级592
12018-01-022-5阴~多云东北风1-2级491
22018-01-032-5多云北风1-2级281
32018-01-040-8东北风1-2级281
42018-01-053-6多云~晴西北风1-2级501

1、Series的排序

df["aqi"].sort_values()
271     21
281     21
249     22
272     22
301     22
      ... 
317    266
71     287
91     287
72     293
86     387
Name: aqi, Length: 365, dtype: int64
df["aqi"].sort_values(ascending=False)
86     387
72     293
91     287
71     287
317    266
      ... 
301     22
272     22
249     22
281     21
271     21
Name: aqi, Length: 365, dtype: int64
df["tianqi"].sort_values()
225     中雨~小雨
230     中雨~小雨
197    中雨~雷阵雨
196    中雨~雷阵雨
112        多云
        ...  
191    雷阵雨~大雨
219     雷阵雨~阴
335      雾~多云
353         霾
348         霾
Name: tianqi, Length: 365, dtype: object

2、DataFrame的排序

2.1 单列排序

df.sort_values(by="aqi")
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
2712018-09-292211北风3-4级211
2812018-10-09154多云~晴西北风4-5级211
2492018-09-072716西北风3-4级221
2722018-09-301913多云西北风4-5级221
3012018-10-29153北风3-4级221
3172018-11-14135多云南风1-2级266重度污染5
712018-03-13175晴~多云南风1-2级287重度污染5
912018-04-022611多云北风1-2级287重度污染5
722018-03-14156多云~阴东北风1-2级293重度污染5
862018-03-28259多云~晴东风1-2级387严重污染6

365 rows × 9 columns

df.sort_values(by="aqi", ascending=False)
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
862018-03-28259多云~晴东风1-2级387严重污染6
722018-03-14156多云~阴东北风1-2级293重度污染5
712018-03-13175晴~多云南风1-2级287重度污染5
912018-04-022611多云北风1-2级287重度污染5
3172018-11-14135多云南风1-2级266重度污染5
2492018-09-072716西北风3-4级221
3012018-10-29153北风3-4级221
2722018-09-301913多云西北风4-5级221
2712018-09-292211北风3-4级211
2812018-10-09154多云~晴西北风4-5级211

365 rows × 9 columns

2.2 多列排序

# 按空气质量等级、最高温度排序,默认升序
df.sort_values(by=["aqiLevel", "bWendu"])
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
3602018-12-27-5-12多云~晴西北风3级481
222018-01-23-4-12西北风3-4级311
232018-01-24-4-11西南风1-2级341
3402018-12-07-4-10西北风3级331
212018-01-22-3-10小雪~多云东风1-2级471
712018-03-13175晴~多云南风1-2级287重度污染5
902018-04-012511晴~多云南风1-2级218重度污染5
912018-04-022611多云北风1-2级287重度污染5
852018-03-272711南风1-2级243重度污染5
862018-03-28259多云~晴东风1-2级387严重污染6

365 rows × 9 columns

# 两个字段都是降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=False)
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
862018-03-28259多云~晴东风1-2级387严重污染6
852018-03-272711南风1-2级243重度污染5
912018-04-022611多云北风1-2级287重度污染5
902018-04-012511晴~多云南风1-2级218重度污染5
712018-03-13175晴~多云南风1-2级287重度污染5
3622018-12-29-3-12西北风2级291
222018-01-23-4-12西北风3-4级311
232018-01-24-4-11西南风1-2级341
3402018-12-07-4-10西北风3级331
3602018-12-27-5-12多云~晴西北风3级481

365 rows × 9 columns

# 分别指定升序和降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=[True, False])
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
1782018-06-283524多云~晴北风1-2级331
1492018-05-303318西风1-2级461
2062018-07-263325多云~雷阵雨东北风1-2级401
1582018-06-083219多云~雷阵雨西南风1-2级431
2052018-07-253225多云北风1-2级281
3172018-11-14135多云南风1-2级266重度污染5
3292018-11-26100多云东南风1级245重度污染5
3352018-12-0292雾~多云东北风1级234重度污染5
572018-02-2770东风1-2级220重度污染5
862018-03-28259多云~晴东风1-2级387严重污染6

365 rows × 9 columns

本文章有配套视频讲解,关注公众号:蚂蚁学Python,查看视频、获取源码

CTR预估:(标签-权重)列表类特征怎么输入到模型?

问题:

要做一个CTR预估模型;

通过之前的数据挖掘,我得到了用户对标签的偏好数据:

[(‘标签1’, 0.8), (‘标签2’, 0.65), (‘标签3’, 0.32), (‘标签4’, 0.05)]

列表的每一个元素包含两个分量,分别是标签、偏好权重;

问题是,这样的一个特征,怎样输入到模型?

我只知道,对于标签1、标签2、标签3这样是分类特征,可以用one hot编码;

然而我不知道这里的权重怎么使用呢?,我想到2种方法:1、先给标签1、标签2、标签3做one-hot编码,然后自己找到每个数字为1的位置,把数字1替换成权重;2、对所有标签映射到一个大数组,找到标签在数组的下标,设置为权重,其他的都是0;

这两种方法哪种更好,或者有其他方法吗?

这个问题也有其他场景:用户的历史行为比如播放的ID列表,统计会得到:

[播放itemid,频次]的列表,怎么作为特征输入到模型?

方法:

1、可以直接把权重作为那一维度的特征吧,就是比如favori_entity_延禧攻略,这个特征,特征值就是weight

2、可以看成特殊的one-hot, 把one-hot里面的1用weight代替,作为一个连续值特征

一种做法,打平成单独维度特征

如果是tensorflow,问题的答案在这个文章:
https://zhuanlan.zhihu.com/p/41663141
超级的详细,1、单个特征有有多分类怎么处理,比如[(‘cat_a’,’cat_b), (cat_b, cat_c)];2、如果是加权cat列表怎么办,比如用户的tag偏好列表:[(‘IT’, 0,8), (‘音乐’,0.6)];

对于第一个问题,用cat_vocu_list加上Indicator_column,第二个,用weighted_categorical_column

Pandas对缺失值的处理

Pandas使用这些函数处理缺失值:
* isnull和notnull:检测是否是空值,可用于df和series
* dropna:丢弃、删除缺失值
– axis : 删除行还是列,{0 or ‘index’, 1 or ‘columns’}, default 0
– how : 如果等于any则任何值为空都删除,如果等于all则所有值都为空才删除
– inplace : 如果为True则修改当前df,否则返回新的df
* fillna:填充空值
– value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
– method : 等于ffill使用前一个不为空的值填充forword fill;等于bfill使用后一个不为空的值填充backword fill
– axis : 按行还是列填充,{0 or ‘index’, 1 or ‘columns’}
– inplace : 如果为True则修改当前df,否则返回新的df

import pandas as pd

实例:特殊Excel的读取、清洗、处理

步骤1:读取excel的时候,忽略前几个空行

studf = pd.read_excel("./datas/student_excel/student_excel.xlsx", skiprows=2)
studf
Unnamed: 0姓名科目分数
0NaN小明语文85.0
1NaNNaN数学80.0
2NaNNaN英语90.0
3NaNNaNNaNNaN
4NaN小王语文85.0
5NaNNaN数学NaN
6NaNNaN英语90.0
7NaNNaNNaNNaN
8NaN小刚语文85.0
9NaNNaN数学80.0
10NaNNaN英语90.0

步骤2:检测空值

studf.isnull()
Unnamed: 0姓名科目分数
0TrueFalseFalseFalse
1TrueTrueFalseFalse
2TrueTrueFalseFalse
3TrueTrueTrueTrue
4TrueFalseFalseFalse
5TrueTrueFalseTrue
6TrueTrueFalseFalse
7TrueTrueTrueTrue
8TrueFalseFalseFalse
9TrueTrueFalseFalse
10TrueTrueFalseFalse
studf["分数"].isnull()
0     False
1     False
2     False
3      True
4     False
5      True
6     False
7      True
8     False
9     False
10    False
Name: 分数, dtype: bool
studf["分数"].notnull()
0      True
1      True
2      True
3     False
4      True
5     False
6      True
7     False
8      True
9      True
10     True
Name: 分数, dtype: bool
# 筛选没有空分数的所有行
studf.loc[studf["分数"].notnull(), :]
Unnamed: 0姓名科目分数
0NaN小明语文85.0
1NaNNaN数学80.0
2NaNNaN英语90.0
4NaN小王语文85.0
6NaNNaN英语90.0
8NaN小刚语文85.0
9NaNNaN数学80.0
10NaNNaN英语90.0

步骤3:删除掉全是空值的列

studf.dropna(axis="columns", how='all', inplace=True)
studf
姓名科目分数
0小明语文85.0
1NaN数学80.0
2NaN英语90.0
3NaNNaNNaN
4小王语文85.0
5NaN数学NaN
6NaN英语90.0
7NaNNaNNaN
8小刚语文85.0
9NaN数学80.0
10NaN英语90.0

步骤4:删除掉全是空值的行

studf.dropna(axis="index", how='all', inplace=True)
studf
姓名科目分数
0小明语文85.0
1NaN数学80.0
2NaN英语90.0
4小王语文85.0
5NaN数学NaN
6NaN英语90.0
8小刚语文85.0
9NaN数学80.0
10NaN英语90.0

步骤5:将分数列为空的填充为0分

studf.fillna({"分数":0})
姓名科目分数
0小明语文85.0
1NaN数学80.0
2NaN英语90.0
4小王语文85.0
5NaN数学0.0
6NaN英语90.0
8小刚语文85.0
9NaN数学80.0
10NaN英语90.0
# 等同于
studf.loc[:, '分数'] = studf['分数'].fillna(0)
studf
姓名科目分数
0小明语文85.0
1NaN数学80.0
2NaN英语90.0
4小王语文85.0
5NaN数学0.0
6NaN英语90.0
8小刚语文85.0
9NaN数学80.0
10NaN英语90.0

步骤6:将姓名的缺失值填充

使用前面的有效值填充,用ffill:forward fill

studf.loc[:, '姓名'] = studf['姓名'].fillna(method="ffill")
studf
姓名科目分数
0小明语文85.0
1小明数学80.0
2小明英语90.0
4小王语文85.0
5小王数学0.0
6小王英语90.0
8小刚语文85.0
9小刚数学80.0
10小刚英语90.0

步骤7:将清洗好的excel保存

studf.to_excel("./datas/student_excel/student_excel_clean.xlsx", index=False)

本文章有配套视频讲解,关注公众号:蚂蚁学Python获取

Pandas的SettingWithCopyWarning报警怎么回事?

本文实例演示报警的复现、原因、解决方案。

0、读取数据

import pandas as pd
fpath = "./datas/beijing_tianqi/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)
df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013℃-6℃晴~多云东北风1-2级592
12018-01-022℃-5℃阴~多云东北风1-2级491
22018-01-032℃-5℃多云北风1-2级281
32018-01-040℃-8℃东北风1-2级281
42018-01-053℃-6℃多云~晴西北风1-2级501
# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')
df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
02018-01-013-6晴~多云东北风1-2级592
12018-01-022-5阴~多云东北风1-2级491
22018-01-032-5多云北风1-2级281
32018-01-040-8东北风1-2级281
42018-01-053-6多云~晴西北风1-2级501

1、复现

# 只选出3月份的数据用于分析
condition = df["ymd"].str.startswith("2018-03")
# 设置温差
df[condition]["wen_cha"] = df["bWendu"]-df["yWendu"]
d:\appdata\python37\lib\site-packages\ipykernel_launcher.py:2: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
# 查看是否修改成功
df[condition].head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
592018-03-018-3多云西南风1-2级461
602018-03-029-1晴~多云北风1-2级952
612018-03-03133多云~阴北风1-2级214重度污染5
622018-03-047-2阴~多云东南风1-2级144轻度污染3
632018-03-058-3南风1-2级942

2、原因

发出警告的代码
df[condition][“wen_cha”] = df[“bWendu”]-df[“yWendu”]

相当于:df.get(condition).set(wen_cha),第一步骤的get发出了报警

链式操作其实是两个步骤,先get后set,get得到的dataframe可能是view也可能是copy,pandas发出警告

官网文档:
https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

核心要诀:pandas的dataframe的修改写操作,只允许在源dataframe上进行,一步到位

3、解决方法1

将get+set的两步操作,改成set的一步操作

df.loc[condition, "wen_cha"] = df["bWendu"]-df["yWendu"]
df[condition].head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwen_cha
592018-03-018-3多云西南风1-2级46111.0
602018-03-029-1晴~多云北风1-2级95210.0
612018-03-03133多云~阴北风1-2级214重度污染510.0
622018-03-047-2阴~多云东南风1-2级144轻度污染39.0
632018-03-058-3南风1-2级94211.0

4、解决方法2

如果需要预筛选数据做后续的处理分析,使用copy复制dataframe

df_month3 = df[condition].copy()
df_month3.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwen_cha
592018-03-018-3多云西南风1-2级46111.0
602018-03-029-1晴~多云北风1-2级95210.0
612018-03-03133多云~阴北风1-2级214重度污染510.0
622018-03-047-2阴~多云东南风1-2级144轻度污染39.0
632018-03-058-3南风1-2级94211.0
df_month3["wen_cha"] = df["bWendu"]-df["yWendu"]
df_month3.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwen_cha
592018-03-018-3多云西南风1-2级46111
602018-03-029-1晴~多云北风1-2级95210
612018-03-03133多云~阴北风1-2级214重度污染510
622018-03-047-2阴~多云东南风1-2级144轻度污染39
632018-03-058-3南风1-2级94211

总之,pandas不允许先筛选子dataframe,再进行修改写入
要么使用.loc实现一个步骤直接修改源dataframe
要么先复制一个子dataframe再一个步骤执行修改


本文章有配套视频讲解,关注公众号:蚂蚁学Python获取: