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

3分钟Python爬取9000张表情包图片

先看下我的爬取成果:

本视频的演示步骤:

  1. 使用requests爬取200个网页
  2. 使用BeautifulSoup实现图片的标题和地址解析
  3. 将图片下载到本地目录

这2个库的详细用法,请看我的其他视频课程

import requests
from bs4 import BeautifulSoup
import re

1、下载共200个页面的HTML

def download_all_htmls():
    """
    下载所有列表页面的HTML,用于后续的分析
    """
    htmls = []
    for idx in range(200):
        url = f"https://fabiaoqing.com/biaoqing/lists/page/{idx+1}.html"
        print("craw html:", url)
        r = requests.get(url)
        if r.status_code != 200:
            raise Exception("error")
        htmls.append(r.text)
    print("success")
    return htmls
# 执行爬取
htmls = download_all_htmls()
craw html: https://fabiaoqing.com/biaoqing/lists/page/1.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/2.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/3.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/4.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/188.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/189.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/190.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/191.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/192.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/193.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/194.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/195.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/196.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/197.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/198.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/199.html
craw html: https://fabiaoqing.com/biaoqing/lists/page/200.html
success
htmls[0][:1000]
'<html>\n\n<head>\n    <meta charset="UTF-8">\n    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">\n    <meta http-equiv="X-UA-Compatible" content="IE=edge">\n    <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n    <title>热门表情_发表情,表情包大全fabiaoqing.com</title>\n    <meta name="Keywords" content="热门表情,表情包,聊天表情,微信表情包,QQ表情包,发表情,表情包大全,表情包下载,表情下载,表情包大战,贴吧表情包,表情包集中营,斗图">\n    <meta name="Description" content="全网热门表情。发表情,最大最全的表情包网站,分享最新最热的表情包、聊天表情、微信表情包、QQ表情包、金馆长表情包、蘑菇头表情包等各类表情。">\n    <meta name="referrer" content="no-referrer" />\n    <link rel="stylesheet" type="text/css" href="//lib.baomitu.com/semantic-ui/2.2.2/semantic.min.css" />\n    <link rel="stylesheet" type="text/css" href="/Public/css/fbq.css?v=2018" />\n    <script data-ad-client="ca-pub-5486123269162001" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>\n    <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.'

2、解析HTML得到所有的图片标题和URL地址

def parse_single_html(html):
    """
    解析单个HTML,得到数据
    @return list((img_title, img_url))
    """
    soup = BeautifulSoup(html, 'html.parser')
    img_divs = soup.find_all("div", class_="tagbqppdiv")
    datas = []
    for img_div in img_divs:
        img_node = img_div.find("img")
        if not img_node: continue
        datas.append((img_node["title"], img_node["data-original"]))
    return datas
import pprint
pprint.pprint(parse_single_html(htmls[0])[:10])
[('阿弥陀佛,施主放下骂图,立地成佛!',
  'http://ww2.sinaimg.cn/bmiddle/9150e4e5gy1g6qlfb10avj20d70f7gmf.jpg'),
 ('看见你就烦(草莓果酱ox白眼 GIF 动图表情包)',
  'http://wx1.sinaimg.cn/bmiddle/006APoFYly1g68tiftpbmg30bh0bh4o5.gif'),
 ('我在哭', 'http://wx3.sinaimg.cn/bmiddle/006qir4ogy1g54eoes2q2j309q09cdgh.jpg'),
 ('我的人生只要这样躺着混日子就很幸福了',
  'http://ww4.sinaimg.cn/bmiddle/9150e4e5gy1g6qm7x6fiuj20mw0mmt9y.jpg'),
 ('草莓果酱ox动图表情包',
  'http://wx1.sinaimg.cn/bmiddle/ceeb653ely1g64664qyc0g20bf0br4jn.gif'),
 ('噗呲 放屁(沙雕羊驼动图表情包)',
  'http://wx1.sinaimg.cn/bmiddle/78b88159gy1g69cze2hkkg20bp0bpx0y.gif'),
 ('来群里转转(熊猫头旋转 GIF 动图)',
  'http://wx1.sinaimg.cn/bmiddle/ceeb653ely1g68tzab8xng207608wwou.gif'),
 ('我爱你(草莓果酱oxGIF 动图表情包)',
  'http://wx2.sinaimg.cn/bmiddle/006APoFYly1g68uwg8djlg30b60b6e57.gif'),
 ('锁屏 带薪拉屎',
  'http://wx3.sinaimg.cn/bmiddle/ceeb653ely1g654hwdsjkg20dc0avgm4.gif'),
 ('我要可爱死你(草莓果酱ox表情包)',
  'http://wx2.sinaimg.cn/bmiddle/bf976b12gy1g68hx2gtleg208c08bk8q.gif')]
# 执行所有的HTML页面的解析
all_imgs = []
for html in htmls:
    all_imgs.extend(parse_single_html(html))
all_imgs[:10]
[('阿弥陀佛,施主放下骂图,立地成佛!',
  'http://ww2.sinaimg.cn/bmiddle/9150e4e5gy1g6qlfb10avj20d70f7gmf.jpg'),
 ('看见你就烦(草莓果酱ox白眼 GIF 动图表情包)',
  'http://wx1.sinaimg.cn/bmiddle/006APoFYly1g68tiftpbmg30bh0bh4o5.gif'),
 ('我在哭', 'http://wx3.sinaimg.cn/bmiddle/006qir4ogy1g54eoes2q2j309q09cdgh.jpg'),
 ('我的人生只要这样躺着混日子就很幸福了',
  'http://ww4.sinaimg.cn/bmiddle/9150e4e5gy1g6qm7x6fiuj20mw0mmt9y.jpg'),
 ('草莓果酱ox动图表情包',
  'http://wx1.sinaimg.cn/bmiddle/ceeb653ely1g64664qyc0g20bf0br4jn.gif'),
 ('噗呲 放屁(沙雕羊驼动图表情包)',
  'http://wx1.sinaimg.cn/bmiddle/78b88159gy1g69cze2hkkg20bp0bpx0y.gif'),
 ('来群里转转(熊猫头旋转 GIF 动图)',
  'http://wx1.sinaimg.cn/bmiddle/ceeb653ely1g68tzab8xng207608wwou.gif'),
 ('我爱你(草莓果酱oxGIF 动图表情包)',
  'http://wx2.sinaimg.cn/bmiddle/006APoFYly1g68uwg8djlg30b60b6e57.gif'),
 ('锁屏 带薪拉屎',
  'http://wx3.sinaimg.cn/bmiddle/ceeb653ely1g654hwdsjkg20dc0avgm4.gif'),
 ('我要可爱死你(草莓果酱ox表情包)',
  'http://wx2.sinaimg.cn/bmiddle/bf976b12gy1g68hx2gtleg208c08bk8q.gif')]
len(all_imgs)
8999

3、下载图片到本地目录

for idx, (title, img_url) in enumerate(all_imgs):
    # 移除标点符号,只保留中文、大小写字母和阿拉伯数字
    reg = "[^0-9A-Za-z\u4e00-\u9fa5]"
    title = re.sub(reg, '', title)

    # 发现了超长的图片标题,做截断
    if len(title)>10: title = title[:10]

    # 得到jpg还是gif后缀
    post_fix = img_url[-3:]
    filename = f"./output/{title}.{post_fix}"

    print(idx, filename)
    img_data = requests.get(img_url)
    with open(filename,"wb")as f:
        f.write(img_data.content)

print("success")
0 ./output/阿弥陀佛施主放下骂图.jpg
1 ./output/看见你就烦草莓果酱o.gif
2 ./output/我在哭.jpg
3 ./output/我的人生只要这样躺着.jpg
4 ./output/草莓果酱ox动图表情.gif
5 ./output/噗呲放屁沙雕羊驼动图.gif
6 ./output/来群里转转熊猫头旋转.gif
7 ./output/我爱你草莓果酱oxG.gif
8 ./output/锁屏带薪拉屎.gif
9 ./output/我要可爱死你草莓果酱.gif
10 ./output/我尼玛傻了都.jpg
11 ./output/你今天表现蛮好10分.gif
12 ./output/真烦人得找个理由做她.gif
13 ./output/哇哦草莓果酱ox表情.jpg
14 ./output/哥哥又说笑了乔碧萝表.gif
15 ./output/锁屏带薪拉屎.gif
16 ./output/我简直难上加难麻将表.jpg

本文有配套视频讲解,关注公众号:蚂蚁学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怎样按条件删除行?

来自:
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)