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获取:

Pandas系列 – 怎样新增数据列?

在进行数据分析时,经常需要按照一定条件创建新的数据列,然后进行进一步分析。

  1. 直接赋值
  2. df.apply方法
  3. df.assign方法
  4. 按条件选择分组分别赋值
    微信公众号:蚂蚁学Python
import pandas as pd

0、读取csv数据到dataframe

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

1、直接赋值的方法

实例:清理温度列,变成数字类型

# 替换掉温度的后缀℃
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

实例:计算温差

# 注意,df["bWendu"]其实是一个Series,后面的减法返回的是Series
df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]
df.head()
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwencha
02018-01-013-6晴~多云东北风1-2级5929
12018-01-022-5阴~多云东北风1-2级4917
22018-01-032-5多云北风1-2级2817
32018-01-040-8东北风1-2级2818
42018-01-053-6多云~晴西北风1-2级5019

2、df.apply方法

Apply a function along an axis of the DataFrame.

Objects passed to the function are Series objects whose index is either the DataFrame’s index (axis=0) or the DataFrame’s columns (axis=1).

实例:添加一列温度类型:
1. 如果最高温度大于33度就是高温
2. 低于-10度是低温
3. 否则是常温

def get_wendu_type(x):
    if x["bWendu"] > 33:
        return '高温'
    if x["yWendu"] < -10:
        return '低温'
    return '常温'

# 注意需要设置axis==1,这是series的index是columns
df.loc[:, "wendu_type"] = df.apply(get_wendu_type, axis=1)
# 查看温度类型的计数
df["wendu_type"].value_counts()
常温    328
高温     29
低温      8
Name: wendu_type, dtype: int64

3、df.assign方法

Assign new columns to a DataFrame.

Returns a new object with all original columns in addition to new ones.

实例:将温度从摄氏度变成华氏度

# 可以同时添加多个新的列
df.assign(
    yWendu_huashi = lambda x : x["yWendu"] * 9 / 5 + 32,
    # 摄氏度转华氏度
    bWendu_huashi = lambda x : x["bWendu"] * 9 / 5 + 32
)
ymdbWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevelwenchawendu_typeyWendu_huashibWendu_huashi
02018-01-013-6晴~多云东北风1-2级5929常温21.237.4
12018-01-022-5阴~多云东北风1-2级4917常温23.035.6
22018-01-032-5多云北风1-2级2817常温23.035.6
32018-01-040-8东北风1-2级2818常温17.632.0
42018-01-053-6多云~晴西北风1-2级5019常温21.237.4
..........................................
3602018-12-27-5-12多云~晴西北风3级4817低温10.423.0
3612018-12-28-3-11西北风3级4018低温12.226.6
3622018-12-29-3-12西北风2级2919低温10.426.6
3632018-12-30-2-11晴~多云东北风1级3119低温12.228.4
3642018-12-31-2-10多云东北风1级5628常温14.028.4

365 rows × 13 columns

4、按条件选择分组分别赋值

按条件先选择数据,然后对这部分数据赋值新列
实例:高低温差大于10度,则认为温差大

# 先创建空列(这是第一种创建新列的方法)
df['wencha_type'] = ''

df.loc[df["bWendu"]-df["yWendu"]>10, "wencha_type"] = "温差大"

df.loc[df["bWendu"]-df["yWendu"]<=10, "wencha_type"] = "温差正常"
df["wencha_type"].value_counts()
温差正常    187
温差大     178
Name: wencha_type, dtype: int64

Pandas系列 – 数据统计函数

  1. 汇总类统计
  2. 唯一去重和按值计数
  3. 相关系数和协方差
import pandas as pd

0、读取csv数据

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

1、汇总类统计

# 一下子提取所有数字列统计结果
df.describe()
bWenduyWenduaqiaqiLevel
count365.000000365.000000365.000000365.000000
mean18.6657538.35890482.1835622.090411
std11.85804611.75505351.9361591.029798
min-5.000000-12.00000021.0000001.000000
25%8.000000-3.00000046.0000001.000000
50%21.0000008.00000069.0000002.000000
75%29.00000019.000000104.0000003.000000
max38.00000027.000000387.0000006.000000
## 查看单个Series的数据
df["bWendu"].mean()
18.665753424657535
# 最高温
df["bWendu"].max()
38
# 最低温
df["bWendu"].min()
-5

2、唯一去重和按值计数

2.1 唯一性去重

一般不用于数值列,而是枚举、分类列

df["fengxiang"].unique()
array(['东北风', '北风', '西北风', '西南风', '南风', '东南风', '东风', '西风'], dtype=object)
df["tianqi"].unique()
array(['晴~多云', '阴~多云', '多云', '阴', '多云~晴', '多云~阴', '晴', '阴~小雪', '小雪~多云',
       '小雨~阴', '小雨~雨夹雪', '多云~小雨', '小雨~多云', '大雨~小雨', '小雨', '阴~小雨',
       '多云~雷阵雨', '雷阵雨~多云', '阴~雷阵雨', '雷阵雨', '雷阵雨~大雨', '中雨~雷阵雨', '小雨~大雨',
       '暴雨~雷阵雨', '雷阵雨~中雨', '小雨~雷阵雨', '雷阵雨~阴', '中雨~小雨', '小雨~中雨', '雾~多云',
       '霾'], dtype=object)
df["fengli"].unique()
array(['1-2级', '4-5级', '3-4级', '2级', '1级', '3级'], dtype=object)

2.2 按值计数

df["fengxiang"].value_counts()
南风     92
西南风    64
北风     54
西北风    51
东南风    46
东北风    38
东风     14
西风      6
Name: fengxiang, dtype: int64
df["tianqi"].value_counts()
晴         101
多云         95
多云~晴       40
晴~多云       34
多云~雷阵雨     14
多云~阴       10
阴~多云        8
小雨~多云       8
雷阵雨         8
雷阵雨~多云      7
小雨          6
多云~小雨       5
阴           4
雷阵雨~中雨      4
中雨~小雨       2
中雨~雷阵雨      2
阴~小雨        2
霾           2
阴~小雪        1
小雪~多云       1
大雨~小雨       1
小雨~雷阵雨      1
小雨~中雨       1
小雨~雨夹雪      1
雾~多云        1
雷阵雨~阴       1
暴雨~雷阵雨      1
小雨~阴        1
雷阵雨~大雨      1
阴~雷阵雨       1
小雨~大雨       1
Name: tianqi, dtype: int64
df["fengli"].value_counts()
1-2级    236
3-4级     68
1级       21
4-5级     20
2级       13
3级        7
Name: fengli, dtype: int64

3、相关系数和协方差

用途(超级厉害):
1. 两只股票,是不是同涨同跌?程度多大?正相关还是负相关?
2. 产品销量的波动,跟哪些因素正相关、负相关,程度有多大?

来自知乎,对于两个变量X、Y:
1. 协方差:衡量同向反向程度,如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;如果协方差为负,说明X,Y反向运动,协方差越小说明反向程度越高。
2. 相关系数:衡量相似度程度,当他们的相关系数为1时,说明两个变量变化时的正向相似度最大,当相关系数为-1时,说明两个变量变化的反向相似度最大

# 协方差矩阵:
df.cov()
bWenduyWenduaqiaqiLevel
bWendu140.613247135.52963347.4626220.879204
yWendu135.529633138.18127416.1866850.264165
aqi47.46262216.1866852697.36456450.749842
aqiLevel0.8792040.26416550.7498421.060485
# 相关系数矩阵
df.corr()
bWenduyWenduaqiaqiLevel
bWendu1.0000000.9722920.0770670.071999
yWendu0.9722921.0000000.0265130.021822
aqi0.0770670.0265131.0000000.948883
aqiLevel0.0719990.0218220.9488831.000000
# 单独查看空气质量和最高温度的相关系数
df["aqi"].corr(df["bWendu"])
0.07706705916811077
df["aqi"].corr(df["yWendu"])
0.02651328267296879
# 空气质量和温差的相关系数
df["aqi"].corr(df["bWendu"]-df["yWendu"])
0.21652257576382047
# !! 这就是特征工程对于机器学习重要性的一个例子
0.21/0.02
10.5

Pandas怎样根据码表更新ID对应的名称?

1、从数据库获取码表

sql = "select category_id, category_name from tb_category"
category_dict = {x["category_name"]:x["category_id"] for x in queryBySql(sql)}

2、在DF中使用apply添加一列新的ID

df.loc[:, "category_id"] = df.apply(
    lambda x : category_dict.get(x["分类"],-1), axis=1
)

这里的axis==1,那么每次遍历的是每个row的Series,这个Series的key是每列的column name.

Pandas怎样按条件删除行?

来自:
https://stackoverflow.com/questions/13851535/delete-rows-from-a-pandas-dataframe-based-on-a-conditional-expression-involving

To directly answer this question’s original title “How to delete rows from a pandas DataFrame based on a conditional expression” (which I understand is not necessarily the OP’s problem but could help other users coming across this question) one way to do this is to use the drop method:

df = df.drop(some labels)

df = df.drop(df[].index)

Example

To remove all rows where column ‘score’ is < 50:

df = df.drop(df[df.score < 50].index)

In place version (as pointed out in comments)

df.drop(df[df.score < 50].index, inplace=True)

Multiple conditions

(see Boolean Indexing)

The operators are: | for or, & for and, and ~ for not. These must be grouped by using parentheses.

To remove all rows where column 'score' is < 50 and > 20

df = df.drop(df[(df.score < 50) & (df.score > 20)].index)

Pandas系列-查询数据的5种方法

今天没有漂亮的PPT,只有干货!!

Pandas查询数据的几种方法

  1. df.loc方法,根据行、列的标签值查询
  2. df.iloc方法,根据行、列的数字位置查询
  3. df.where方法
  4. df.query方法

.loc既能查询,又能覆盖写入,强烈推荐!

Pandas使用df.loc查询数据的方法

  1. 使用单个label值查询数据
  2. 使用值列表批量查询
  3. 使用数值区间进行范围查询
  4. 使用条件表达式查询
  5. 调用函数查询

注意

  • 以上查询方法,既适用于行,也适用于列
  • 注意观察降维dataFrame>Series>值

微信公众号:【蚂蚁学Python】,Python原创免费视频分享

import pandas as pd

0、读取数据

数据为北京2018年全年天气预报
该数据的爬虫教程参见我的Python爬虫系列视频课程

df = pd.read_csv("./datas/beijing_tianqi/beijing_tianqi_2018.csv")
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.set_index('ymd', inplace=True)
# 时间序列见后续课程,本次按字符串处理
df.index
Index(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04', '2018-01-05',
       '2018-01-06', '2018-01-07', '2018-01-08', '2018-01-09', '2018-01-10',
       ...
       '2018-12-22', '2018-12-23', '2018-12-24', '2018-12-25', '2018-12-26',
       '2018-12-27', '2018-12-28', '2018-12-29', '2018-12-30', '2018-12-31'],
      dtype='object', name='ymd', length=365)
df.head()
bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-01-013℃-6℃晴~多云东北风1-2级592
2018-01-022℃-5℃阴~多云东北风1-2级491
2018-01-032℃-5℃多云北风1-2级281
2018-01-040℃-8℃东北风1-2级281
2018-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.dtypes
bWendu        int32
yWendu        int32
tianqi       object
fengxiang    object
fengli       object
aqi           int64
aqiInfo      object
aqiLevel      int64
dtype: object
df.head()
bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-01-013-6晴~多云东北风1-2级592
2018-01-022-5阴~多云东北风1-2级491
2018-01-032-5多云北风1-2级281
2018-01-040-8东北风1-2级281
2018-01-053-6多云~晴西北风1-2级501

1、使用单个label值查询数据

行或者列,都可以只传入单个值,实现精确匹配

# 得到单个值
df.loc['2018-01-03', 'bWendu']
2
# 得到一个Series
df.loc['2018-01-03', ['bWendu', 'yWendu']]
bWendu     2
yWendu    -5
Name: 2018-01-03, dtype: object

2、使用值列表批量查询

# 得到Series
df.loc[['2018-01-03','2018-01-04','2018-01-05'], 'bWendu']
ymd
2018-01-03    2
2018-01-04    0
2018-01-05    3
Name: bWendu, dtype: int32
# 得到DataFrame
df.loc[['2018-01-03','2018-01-04','2018-01-05'], ['bWendu', 'yWendu']]
bWenduyWendu
ymd
2018-01-032-5
2018-01-040-8
2018-01-053-6

3、使用数值区间进行范围查询

注意:区间既包含开始,也包含结束

# 行index按区间
df.loc['2018-01-03':'2018-01-05', 'bWendu']
ymd
2018-01-03    2
2018-01-04    0
2018-01-05    3
Name: bWendu, dtype: int32
# 列index按区间
df.loc['2018-01-03', 'bWendu':'fengxiang']
bWendu        2
yWendu       -5
tianqi       多云
fengxiang    北风
Name: 2018-01-03, dtype: object
# 行和列都按区间查询
df.loc['2018-01-03':'2018-01-05', 'bWendu':'fengxiang']
bWenduyWendutianqifengxiang
ymd
2018-01-032-5多云北风
2018-01-040-8东北风
2018-01-053-6多云~晴西北风

4、使用条件表达式查询

bool列表的长度得等于行数或者列数

简单条件查询,最低温度低于-10度的列表

df.loc[df["yWendu"]<-10, :]
bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-01-23-4-12西北风3-4级311
2018-01-24-4-11西南风1-2级341
2018-01-25-3-11多云东北风1-2级271
2018-12-26-2-11晴~多云东北风2级261
2018-12-27-5-12多云~晴西北风3级481
2018-12-28-3-11西北风3级401
2018-12-29-3-12西北风2级291
2018-12-30-2-11晴~多云东北风1级311
# 观察一下这里的boolean条件
df["yWendu"]<-10
ymd
2018-01-01    False
2018-01-02    False
2018-01-03    False
2018-01-04    False
2018-01-05    False
              ...  
2018-12-27     True
2018-12-28     True
2018-12-29     True
2018-12-30     True
2018-12-31    False
Name: yWendu, Length: 365, dtype: bool

复杂条件查询,查一下我心中的完美天气

注意,组合条件用&符号合并,每个条件判断都得带括号

## 查询最高温度小于30度,并且最低温度大于15度,并且是晴天,并且天气为优的数据
df.loc[(df["bWendu"]<=30) & (df["yWendu"]>=15) & (df["tianqi"]=='晴') & (df["aqiLevel"]==1), :]
bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-08-243020北风1-2级401
2018-09-072716西北风3-4级221

我哭,北京好天气这么稀少!!

# 再次观察这里的boolean条件
(df["bWendu"]<=30) & (df["yWendu"]>=15) & (df["tianqi"]=='晴') & (df["aqiLevel"]==1)
ymd
2018-01-01    False
2018-01-02    False
2018-01-03    False
2018-01-04    False
2018-01-05    False
              ...  
2018-12-27    False
2018-12-28    False
2018-12-29    False
2018-12-30    False
2018-12-31    False
Length: 365, dtype: bool

5、调用函数查询

# 直接写lambda表达式
df.loc[lambda df : (df["bWendu"]<=30) & (df["yWendu"]>=15), :]
bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-04-282717西南风3-4级125轻度污染3
2018-04-293016多云南风3-4级193中度污染4
2018-05-042716晴~多云西南风1-2级862
2018-05-092917晴~多云西南风3-4级792
2018-05-102618多云南风3-4级118轻度污染3
2018-09-152615多云北风3-4级421
2018-09-172717多云~阴北风1-2级371
2018-09-182517阴~多云西南风1-2级501
2018-09-192617多云南风1-2级522
2018-09-202716多云西南风1-2级632

64 rows × 8 columns

# 编写自己的函数,查询9月份,空气质量好的数据
def query_my_data(df):
    return df.index.str.startswith("2018-09") & df["aqiLevel"]==1

df.loc[query_my_data, :]
bWenduyWendutianqifengxiangfengliaqiaqiInfoaqiLevel
ymd
2018-09-012719阴~小雨南风1-2级501
2018-09-043118西南风3-4级241
2018-09-053119晴~多云西南风3-4级341
2018-09-062718多云~晴西北风4-5级371
2018-09-072716西北风3-4级221
2018-09-082715多云~晴北风1-2级281
2018-09-132920多云~阴南风1-2级107轻度污染3
2018-09-142819小雨~多云南风1-2级128轻度污染3
2018-09-152615多云北风3-4级421
2018-09-162514多云~晴北风1-2级291
2018-09-172717多云~阴北风1-2级371
2018-09-182517阴~多云西南风1-2级501
2018-09-212514西北风3-4级501
2018-09-222413西北风3-4级281
2018-09-232312西北风4-5级281
2018-09-242311北风1-2级281
2018-09-252412晴~多云南风1-2级441
2018-09-292211北风3-4级211
2018-09-301913多云西北风4-5级221

本文的代码地址:https://github.com/peiss/ant-learn-pandas
本文的视频地址:微信公众号:蚂蚁学Python

Pandas系列-DataFrame和Series数据结构

本代码演示:
1. pandas读取纯文本文件
* 读取csv文件
* 读取txt文件
2. pandas读取xlsx格式excel文件
3. pandas读取mysql数据表

import pandas as pd

1、读取纯文本文件

1.1 读取CSV,使用默认的标题行、逗号分隔符

fpath = "./datas/ml-latest-small/ratings.csv"
# 使用pd.read_csv读取数据
ratings = pd.read_csv(fpath)
# 查看前几行数据
ratings.head()
userIdmovieIdratingtimestamp
0114.0964982703
1134.0964981247
2164.0964982224
31475.0964983815
41505.0964982931
# 查看数据的形状,返回(行数、列数)
ratings.shape
(100836, 4)
# 查看列名列表
ratings.columns
Index(['userId', 'movieId', 'rating', 'timestamp'], dtype='object')
# 查看索引列
ratings.index
RangeIndex(start=0, stop=100836, step=1)
# 查看每列的数据类型
ratings.dtypes
userId         int64
movieId        int64
rating       float64
timestamp      int64
dtype: object

1.2 读取txt文件,自己指定分隔符、列名

fpath = "./datas/crazyant/access_pvuv.txt"
pvuv = pd.read_csv(
    fpath,
    sep="\t",
    header=None,
    names=['pdate', 'pv', 'uv']
)
pvuv
pdatepvuv
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

2、读取excel文件

fpath = "./datas/crazyant/access_pvuv.xlsx"
pvuv = pd.read_excel(fpath)
pvuv
日期PVUV
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

3、读取MySQL数据库

import pymysql
conn = pymysql.connect(
        host='127.0.0.1',
        user='root',
        password='12345678',
        database='test',
        charset='utf8'
    )
mysql_page = pd.read_sql("select * from crazyant_pvuv", con=conn)
mysql_page
pdatepvuv
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

本文的代码地址:https://github.com/peiss/ant-learn-pandas
本文的视频地址:微信公众号:蚂蚁学Python

Pandas系列-读取csv/excel/mysql数据

本代码演示:
1. pandas读取纯文本文件
* 读取csv文件
* 读取txt文件
2. pandas读取xlsx格式excel文件
3. pandas读取mysql数据表

import pandas as pd

1、读取纯文本文件

1.1 读取CSV,使用默认的标题行、逗号分隔符

fpath = "./datas/ml-latest-small/ratings.csv"
# 使用pd.read_csv读取数据
ratings = pd.read_csv(fpath)
# 查看前几行数据
ratings.head()
userIdmovieIdratingtimestamp
0114.0964982703
1134.0964981247
2164.0964982224
31475.0964983815
41505.0964982931
# 查看数据的形状,返回(行数、列数)
ratings.shape
(100836, 4)
# 查看列名列表
ratings.columns
Index(['userId', 'movieId', 'rating', 'timestamp'], dtype='object')
# 查看索引列
ratings.index
RangeIndex(start=0, stop=100836, step=1)
# 查看每列的数据类型
ratings.dtypes
userId         int64
movieId        int64
rating       float64
timestamp      int64
dtype: object

1.2 读取txt文件,自己指定分隔符、列名

fpath = "./datas/crazyant/access_pvuv.txt"
pvuv = pd.read_csv(
    fpath,
    sep="\t",
    header=None,
    names=['pdate', 'pv', 'uv']
)
pvuv
pdatepvuv
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

2、读取excel文件

fpath = "./datas/crazyant/access_pvuv.xlsx"
pvuv = pd.read_excel(fpath)
pvuv
日期PVUV
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

3、读取MySQL数据库

import pymysql
conn = pymysql.connect(
        host='127.0.0.1',
        user='root',
        password='12345678',
        database='test',
        charset='utf8'
    )
mysql_page = pd.read_sql("select * from crazyant_pvuv", con=conn)
mysql_page
pdatepvuv
02019-09-1013992
12019-09-09185153
22019-09-0812359
32019-09-076540
42019-09-0615798
52019-09-05205151
62019-09-04196167
72019-09-03216176
82019-09-02227148
92019-09-0110561

本文的代码地址:https://github.com/peiss/ant-learn-pandas
本文的视频地址:微信公众号:蚂蚁学Python

推荐系统:实现文章相似推荐的简单实例

看了一篇文章实现了文章的内容相似度计算实现相似推荐,算法比较简单,非常适合我这种初学入门的人。

来自一篇英文文章:地址

文章标题为:How to build a content-based movie recommender system with Natural Language Processing

文章的代码在:地址

该文章实现相似推荐的步骤:

1、将CSV加载到pandas.pd

2、提取其中的标题、题材分类、导演、演员、情节描述4个字段;

3、将单词都变小写,人名中的空格合并(英文才需要这样);

4、题材分类、导演、演员这几个特征都是结构化的不需要处理;而标题、情节描述这类字段是长段文本,使用nltk库做关键词提取(如果是中文可以用jieba分词库也有关键词提取功能)

5、将第四步骤的分类、导演、演员、关键词列表,合并到一个词列表(这一处理其实暗含了分类、导演、演员三个特征和关键词一样重要,没有做加权处理)

6、使用CountVectorizer做每个词语的计数,得到了每个文章的向量;

7、使用sklearn的cosin做笛卡尔积的相似度计算;

8、计算结果是一个二维矩阵,按行查询某一个文章的推荐结果,按相似度值排序得到最相似的文章

从里面能学到不少知识的运用:

1、全流程用pandas运行,尤其是for each row,做单个列的各种map计算;

2、计算相似度时使用了多个特征,包括Title,Genre,Director,Actors,Plot,统一成一个bag of words参与计算

3、使用from sklearn.metrics.pairwise import cosine_similarity用于相似度计算;

4、使用from sklearn.feature_extraction.text import CountVectorizer用于单词计数;

5、使用from rake_nltk import Rake用于关键词提取;

代码实现关键部分:

作者用到的一些库:

import pandas as pd
from rake_nltk import Rake
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import CountVectorizer

pandas的dataframe中,直接替换一列的语法:

df['Director'] = df['Director'].map(lambda x: x.split(' '))

pd按行以此处理某个列的方法:

for index, row in df.iterrows():
    row['Actors'] = [x.lower().replace(' ','') for x in row['Actors']]
    row['Director'] = ''.join(row['Director']).lower()

pd.df删除某一列的方法:

df.drop(columns = ['Plot'], inplace = True)

pd.df从columns中提取一列作为index的方法:

df.set_index('Title', inplace = True)

作者将能使用的所有列,都放在了一个词包中用于相似度计算,按我的想法,这些特征列其实应该有不同的权重?

df['bag_of_words'] = ''
columns = df.columns
for index, row in df.iterrows():
    words = ''
    for col in columns:
        if col != 'Director':
            words = words + ' '.join(row[col])+ ' '
        else:
            words = words + row[col]+ ' '
    row['bag_of_words'] = words
    
df.drop(columns = [col for col in df.columns if col!= 'bag_of_words'], inplace = True)

sklearn使用词计数的调用:

count = CountVectorizer()
count_matrix = count.fit_transform(df['bag_of_words'])

sklearn实现矩阵相似度计算的方法:

# generating the cosine similarity matrix
cosine_sim = cosine_similarity(count_matrix, count_matrix)

怎样实现不同特征列的融合相似度计算?

这个问题纠结我很久,查询了一些文章,大都是人工指定加权权重,或者使用模型拟合权重值,没有多么简单的方法,而作者使用的其实是直接把分类、演员等字段,和关键词直接融合的方法

作者在文章中提到一句话:

I decided to use CountVectorizer rather than TfIdfVectorizer for one simple reason: I need a simple frequency counter for each word in my bag_of_words column. Tf-Idf tends to give less importance to the words that are more present in the entire corpus (our whole column, in this case) which is not what we want for this application, because every word is important to detect similarity!

对于标题、介绍这种纯文本内容,我们可以用TF/IDF提取关键词,物理含义就是降低全局出现的词频很多的词语;但是其实对于作者、演员、题材这类特征列,他们并不需要降低全局词频,使用词频计数即可。

有哪些可以提升的地方

作者的方法确实可以实现相似推荐,不过我感觉有一些可以提升的地方:

1、标题、简介,提取关键词后,可以查询业界的word2vec做向量扩展,这样能实现恰恰和伦巴舞这类词语的相似度度量,直接的关键词查询是得不到这样的信息;

2、分类、导演、演员这三个特征,需要和描述得到的关键词区分开,可以用加权的方法进行,按照产品的需求,加重分类、导演的相似度权重,降低演员、关键词的权重等,如果需要可以从点击率等出发,用模型计算这些权重;

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