于贵洋的博客

BI、数据分析


  • 首页

  • 分类

  • 标签

  • 归档

  • 站点地图

  • 公益404

  • 关于

  • 搜索

Pandas手册(12)- 时间序列

发表于 2017-08-17 | 分类于 Python-Pandas

Python
Pandas


在数据分析中,时间序列应该很常见,这里,我们看看在pandas里面的使用

1. 日期和时间数据类型

经常使用的datetime,time,及calendar模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from datetime import datetime
now = datetime.now()
now
Out[33]: datetime.datetime(2017, 8, 18, 9, 43, 46, 360886)
now.year
Out[34]: 2017
now.month
Out[35]: 8
now.day
Out[36]: 18

datetime.timedelta表示2个datetime对象的时间差

1
2
3
4
5
6
7
8
9
10
a = datetime(2018,8,18) - datetime(2018,8,17)
a
Out[38]: datetime.timedelta(1)
a.days
Out[39]: 1
a.seconds
Out[40]: 0

1
2
class datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
A timedelta object represents a duration, the difference between two dates or times.

我们可以给datetime加上或者减去一个或多个timedelta

1
2
3
4
5
6
7
8
9
from datetime import timedelta
start = datetime(2017,8,18)
start + timedelta(days=-12)
Out[44]: datetime.datetime(2017, 8, 6, 0, 0)
start + timedelta(seconds=600)
Out[45]: datetime.datetime(2017, 8, 18, 0, 10)

2. 日期转换

1
pandas.to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=None, box=True, format=None, exact=True, unit=None, infer_datetime_format=False, origin='unix')

dayfirst参数

1
2
3
4
5
6
7
#比如有时候,我们的格式,可能是day在前面,默认的话,会转换为 月/日/年
pd.to_datetime(['06/08/2017','07/08/2017'])
Out[29]: DatetimeIndex(['2017-06-08', '2017-07-08'], dtype='datetime64[ns]', freq=None)
#使用dayfirst,指定日期,日/月/年
pd.to_datetime(['06/08/2017','07/08/2017'],dayfirst=True)
Out[30]: DatetimeIndex(['2017-08-06', '2017-08-07'], dtype='datetime64[ns]', freq=None)

我们可以将一个包含日期信息的DataFrame封装成datetime

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
df = pd.DataFrame({'year': [2015, 2016],
'month': [2, 3],
'day': [4, 5]})
df
Out[32]:
day month year
0 4 2 2015
1 5 3 2016
pd.to_datetime(df)
Out[33]:
0 2015-02-04
1 2016-03-05
dtype: datetime64[ns]

这样转换的时候,是一定需要,最少满足年月日3列,不然会报错

ValueError: to assemble mappings requires at least that [year, month, day] be specified: [day,month] is missing

errors参数

1
2
3
4
5
errors : {‘ignore’, ‘raise’, ‘coerce’}, default ‘raise’
If ‘raise’, then invalid parsing will raise an exception
If ‘coerce’, then invalid parsing will be set as NaT
If ‘ignore’, then invalid parsing will return the input

如果一个日期不符合规范,默认是会报错的,我们可以通过errors参数来控制

1
2
3
4
5
6
7
8
pd.to_datetime('13/13/2017')
ValueError: month must be in 1..12
pd.to_datetime('13/13/2017',errors='ignore')
Out[38]: '13/13/2017'
pd.to_datetime('13/13/2017',errors='coerce')
Out[39]: NaT

这个NaT,就是Not a Time,在时间序列里面表示NA值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
pd.to_datetime(1)
Out[21]: Timestamp('1970-01-01 00:00:00.000000001')
pd.to_datetime(10)
Out[22]: Timestamp('1970-01-01 00:00:00.000000010')
s1 = pd.Series(['2017-01-01','2017-02-01','2017-03-01']*3)
s1
Out[24]:
0 2017-01-01
1 2017-02-01
2 2017-03-01
3 2017-01-01
4 2017-02-01
5 2017-03-01
6 2017-01-01
7 2017-02-01
8 2017-03-01
dtype: object
pd.to_datetime(s1)
Out[25]:
0 2017-01-01
1 2017-02-01
2 2017-03-01
3 2017-01-01
4 2017-02-01
5 2017-03-01
6 2017-01-01
7 2017-02-01
8 2017-03-01
dtype: datetime64[ns]

3. 时间序列基础

最基本的时间序列类型,就是以时间戳为索引的Series

1
2
3
4
5
6
7
8
9
10
11
12
13
14
s = pd.Series(np.random.randn(3),index=[datetime(2018,8,1),datetime(2018,8,2),datetime(2018,8,3)])
s
Out[52]:
2018-08-01 0.360137
2018-08-02 1.422533
2018-08-03 -1.079172
dtype: float64
s.index
Out[53]: DatetimeIndex(['2018-08-01', '2018-08-02', '2018-08-03'], dtype='datetime64[ns]', freq=None)
type(s)
Out[54]: pandas.core.series.Series

不同索引的时间序列之间的算术运算会按时间自动对齐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
s+s[1:]
Out[56]:
2018-08-01 NaN
2018-08-02 2.845066
2018-08-03 -2.158345
dtype: float64
s
Out[57]:
2018-08-01 0.360137
2018-08-02 1.422533
2018-08-03 -1.079172
dtype: float64
s[1:]
Out[58]:
2018-08-02 1.422533
2018-08-03 -1.079172
dtype: float64

4. 索引、选取、子集构造

对于时间序列的处理,有很方便的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
longer_ts = pd.Series(np.random.randn(1000),
index=pd.date_range('1/1/2000', periods=1000))
longer_ts.head()
Out[76]:
2000-01-01 -0.617652
2000-01-02 1.331210
2000-01-03 0.351012
2000-01-04 -1.686123
2000-01-05 -0.426614
Freq: D, dtype: float64
longer_ts['2000-01-01':'2000-01-04']
Out[77]:
2000-01-01 -0.617652
2000-01-02 1.331210
2000-01-03 0.351012
2000-01-04 -1.686123
Freq: D, dtype: float64
longer_ts['01/01/2000':'01/04/2000']
Out[78]:
2000-01-01 -0.617652
2000-01-02 1.331210
2000-01-03 0.351012
2000-01-04 -1.686123
Freq: D, dtype: float64

对于DataFrame来说,也是一样的

1
2
3
4
pandas.date_range(start=None, end=None, periods=None, freq='D', tz=None, normalize=False, name=None, closed=None, **kwargs)
Return a fixed frequency datetime index, with day (calendar) as the default frequency
freq参数可以参考网址:http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#从2017-01-01开始,每个周三,生成100个
dates = pd.date_range('1/1/2017', periods=100, freq='W-WED')
long_df = pd.DataFrame(np.random.randn(100, 4),
index=dates,
columns=['Colorado', 'Texas', 'New York', 'Ohio'])
long_df.head()
Out[92]:
Colorado Texas New York Ohio
2017-01-04 -1.061954 0.324256 1.532633 -0.310599
2017-01-11 1.211990 -0.241169 -0.488018 -0.473085
2017-01-18 0.112726 -0.021406 -0.903449 -1.191892
2017-01-25 0.247537 -0.086301 1.252001 1.119687
2017-02-01 -0.058160 -0.856956 -0.783473 0.081420
#选取1月份所有数据
long_df.loc['2017-01']
Out[94]:
Colorado Texas New York Ohio
2017-01-04 -1.061954 0.324256 1.532633 -0.310599
2017-01-11 1.211990 -0.241169 -0.488018 -0.473085
2017-01-18 0.112726 -0.021406 -0.903449 -1.191892
2017-01-25 0.247537 -0.086301 1.252001 1.119687

Pandas手册(11)- groupby

发表于 2017-08-16 | 分类于 Python-Pandas

Python
Pandas


这里,我们整理下pandas中关于groupby的使用,和SQL中一样,就是对数据进行聚合
可以参考官方:
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html
http://pandas.pydata.org/pandas-docs/stable/groupby.html

1. groupby基本使用

1
2
DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)
Group series using mapper (dict or key function, apply given function to group, return result as series) or by a series of columns.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np
df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
'key2' : ['one', 'two', 'one', 'two', 'one'],
'data1' : np.random.randint(0,10,5),
'data2' : np.random.randint(0,10,5)})
df
Out[158]:
data1 data2 key1 key2
0 2 4 a one
1 3 8 a two
2 6 5 b one
3 7 3 b two
4 7 6 a one

我们现在,根据key1来groupby

1
2
3
4
a = df.groupby(by=['key1'])
a
Out[170]: <pandas.core.groupby.DataFrameGroupBy object at 0x000000000B8317F0>

我们可以看到,返回值是一个DataFrameGroupBy对象,这只是一个中间数据,还没有进行真正的聚合
这里有一个概念”split-apply-combine”,拆分-应用-合并,感觉和MapReduce的概念差不多,这个的groupby就是做了拆分
我们可以遍历DataFrameGroupBy,

1
2
3
4
5
6
7
8
9
10
11
12
13
for k,v in a:
print('k:',k)
print('v:',v)
k: a
v: data1 data2 key1 key2
0 2 4 a one
1 3 8 a two
4 7 6 a one
k: b
v: data1 data2 key1 key2
2 6 5 b one
3 7 3 b two

这个就是将内容进行了拆分,当我们在调用统计函数时,才会执行应用和合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
a.sum()
Out[172]:
data1 data2
key1
a 12 18
b 13 8
a.size()
Out[173]:
key1
a 3
b 2
dtype: int64
a.count()
Out[174]:
data1 data2 key2
key1
a 3 3 3
b 2 2 2
a.max()
Out[175]:
data1 data2 key2
key1
a 7 8 two
b 7 5 two
a.mean()
Out[176]:
data1 data2
key1
a 4.0 6.0
b 6.5 4.0

我们可以按2个值进行聚合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
df
Out[188]:
data1 data2 key1 key2
0 2 4 a one
1 3 8 a two
2 6 5 b one
3 7 3 b two
4 7 6 a one
df.groupby(by=['key1','key2']).sum()
Out[189]:
data1 data2
key1 key2
a one 9 10
two 3 8
b one 6 5
two 7 3

默认的话,会将数值类型的字段做聚合,我们也可以选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
df.groupby(by=['key1','key2'])['data1'].sum()
Out[190]:
key1 key2
a one 9
two 3
b one 6
two 7
Name: data1, dtype: int32
df.groupby(by=['key1','key2'])['data1','data2'].sum()
Out[191]:
data1 data2
key1 key2
a one 9 10
two 3 8
b one 6 5
two 7 3

下面的写法也是同样的,前面我们是直接传入的列名,这里我们传入series也可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
df.groupby(by=df['key1']).sum()
Out[197]:
data1 data2
key1
a 12 18
b 13 8
df.groupby(by=[df['key1'],df['key2']]).sum()
Out[198]:
data1 data2
key1 key2
a one 9 10
two 3 8
b one 6 5
two 7 3

上面我们传入的都是当前df的序列,这里也可以传入新的,这里只要长度符合就行了,感觉就是把它当成新列来处理

1
2
3
4
5
df.groupby(by=['lufei','lufei','lufei','lufei','namei']).sum()
Out[199]:
data1 data2
lufei 18 20
namei 7 6

1
2
3
by : mapping, function, str, or iterable
Used to determine the groups for the groupby. If by is a function, it’s called on each value of the object’s index. If a dict or Series is passed, the Series or dict VALUES will be used to determine the groups (the Series’ values are first aligned; see .align() method). If an ndarray is passed, the values are used as-is determine the groups. A str or list of strs may be passed to group by the columns in self

这个by参数,还可以接收一个dict,像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
df
Out[204]:
data1 data2 key1 key2
0 2 4 a one
1 3 8 a two
2 6 5 b one
3 7 3 b two
4 7 6 a one
df.index
Out[205]: RangeIndex(start=0, stop=5, step=1)
df
Out[206]:
data1 data2 key1 key2
0 2 4 a one
1 3 8 a two
2 6 5 b one
3 7 3 b two
4 7 6 a one
#默认是根据啊axis=0,所以groupby之前会先将index和dict进行映射,
df.groupby({0:'a',1:'a',2:'a',3:'a',4:'a'}).sum()
Out[207]:
data1 data2
a 25 26

这里,对于series也是一样的,series也有index,
更厉害的是,这里还可以使用函数进行分组,函数会在各个索引值上调用一次,然后根据返回值来用作分组名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
df
Out[216]:
data1 data2 key1 key2
0 2 4 a one
1 3 8 a two
2 6 5 b one
3 7 3 b two
4 7 6 a one
#会把每一个index的值加10,然后再聚合
df.groupby(lambda x:x+10).sum()
Out[217]:
data1 data2
10 2 4
11 3 8
12 6 5
13 7 3
14 7 6

—————update at 2017-08-23
这里继续整理下pandas中groupby的使用

2. 面向列的多函数应用

上面,我们再对列做聚合的时候,都是使用使用统一的函数,比如sum(),count(),都是一起的,
在pandas中,我们可以同时调用多个函数,主要是使用agg

1
2
3
4
5
6
7
8
9
10
11
12
13
DataFrameGroupBy.agg(arg, *args, **kwargs)
Aggregate using callable, string, dict, or list of string/callables
func : callable, string, dictionary, or list of string/callables
Function to use for aggregating the data. If a function, must either work when passed a DataFrame or when passed to DataFrame.apply. For a DataFrame, can pass a dict, if the keys are DataFrame column names.
Accepted Combinations are:
string function name
function
list of functions
dict of column names -> functions (or list of functions)

小栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
df = pd.DataFrame({'A': [1, 1, 2, 2],
'B': [1, 2, 3, 4],
'C': np.random.randn(4)})
df
Out[64]:
A B C
0 1 1 0.433076
1 1 2 0.509764
2 2 3 -1.091318
3 2 4 -0.696079
df.groupby(by=['A']).min()
Out[65]:
B C
A
1 1 0.433076
2 3 -1.091318
#使用agg,调用min函数,和直接调用时等价的
df.groupby(by=['A']).agg('min')
Out[66]:
B C
A
1 1 0.433076
2 3 -1.091318
#还可以传入一个函数数组,同时调用min和max
df.groupby(by=['A']).agg(['min','max'])
Out[67]:
B C
min max min max
A
1 1 2 0.433076 0.509764
2 3 4 -1.091318 -0.696079
df.groupby(by=['A'])['B'].agg(['min','max'])
Out[68]:
min max
A
1 1 2
2 3 4
#还可以通过传入一个dict,来对不同的列做不同的操作,列名为key,func为value
df.groupby(by=['A']).agg({'B':['min','max'],'C':['sum']})
Out[69]:
B C
min max sum
A
1 1 2 0.942840
2 3 4 -1.787397

上面,我们传入函数,默认会用我们的函数名来做列名,但,有时我们想要自定义,
我们通过传入一个(name,function)的列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
df.groupby(by=['A']).agg([('the_min_data','min'),('the_max_data','max')])
Out[73]:
B C
the_min_data the_max_data the_min_data the_max_data
A
1 1 2 0.433076 0.509764
2 3 4 -1.091318 -0.696079
#可以随意组合
df.groupby(by=['A']).agg({'B':['min','max'],'C':[('hey_sum','sum')]})
Out[74]:
B C
min max hey_sum
A
1 1 2 0.942840
2 3 4 -1.787397

3. 已无索引形式返回聚合数据

前面,我们groupby之后,都是用聚合建来当做index,我们可以通过参数as_index=False,来取消

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#会默认生成一个新index
df.groupby(by=['A','B'],as_index=False).max()
Out[80]:
A B C
0 1 1 0.433076
1 1 2 0.509764
2 2 3 -1.091318
3 2 4 -0.696079
df.groupby(by=['A','B'],as_index=True).max()
Out[81]:
C
A B
1 1 0.433076
2 0.509764
2 3 -1.091318
4 -0.696079

做了练习之后,这里发现,直接调用函数是好用的,但是,如果使用agg来调用,是不好用的这个参数

1
2
3
4
5
6
7
8
9
df.groupby(by=['A','B'],as_index=False).agg(['min','max'])
Out[79]:
C
min max
A B
1 1 0.433076 0.433076
2 0.509764 0.509764
2 3 -1.091318 -1.091318
4 -0.696079 -0.696079

爬虫小实例-1688物流信息之发货地信息获取

发表于 2017-08-15 | 分类于 Python-爬虫

这里写个例子,公司的一个大神之前爬过1688上面的物流信息,这里也来试一下,顺便分享下学习过程。

背景介绍

目标网页:https://56.1688.com/order/price/estimate_price.htm
目的:抓取网站上所有的线路信息,保存到文件或数据库中。

实践步骤

先观察下网站的特征,随便查询一下看看,主要看看URL是怎么传递参数的,通过FireBug,下面几个参数是不为空的
图片.png

通过查看网页源码,发现上面的参数,就是发货地和收获地的省份、城市、区县的编码

既然我们要获取所有的线路数据,那第一步就是获取这里所有的发货地、收货地信息

一开始以为这个编码是1688上自定义的,后来查了一下,发现是官方的编码,这也是为啥,前面会写一篇《最新行政区信息获取》

所以,这里最方便的办法就是直接使用官方的编码,第一步就解决了;
但是前面呢,既然要学习爬虫,就用爬虫来试试,正好前面学了selenium,这里就熟练掌握一下吧。
实践的时候呢,还是遇到了一些问题
比如:默认省份信息是隐藏的(display: none),城市和区县信息的动态的切换的

这个应该使用JS来控制的,但是一直没找到是哪段JS
还好selenium中可以模拟单击事件,很方便
下面是代码,该有的注释都在,效率比较差,也就3000多条记录,还好跑一次就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 14 21:20:56 2017
@author: yuguiyang
"""
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
#打开浏览器
browser = webdriver.Firefox()
#设置等待时长,最长等待10s
wait = WebDriverWait(browser,10)
#单击省份标签
def click_province():
#这里不点击的话,下面可以通过属性获取省份名称,但是直接使用text是不行的
li_labels = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#source-area-select ul.h li span.inner')))
li_labels[1].click()
#单击城市标签
def click_city():
li_labels = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#source-area-select ul.h li span.inner')))
li_labels[2].click()
def main():
#打开URL
browser.get('https://56.1688.com/order/price/estimate_price.htm')
#输出浏览器标题
print('browser title: ',browser.title)
#单击发货输入框,显示城市选择的标签
input_start = wait.until(EC.presence_of_element_located((By.ID,'source-area')))
input_start.click()
#单击省份标签
click_province()
#区域信息
div_tabs = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#source-area-select div.s-tab-b')))
#只使用省份
li_provinces = div_tabs[1].find_elements(By.CSS_SELECTOR ,'a.panel-item')
file = open('1688_line.txt','w')
#遍历每一个省份
for pro in li_provinces:
#单击当前的省份,页面会跳转到该省份的城市列表
pro.click()
#获取城市信息
div_tabs = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#source-area-select div.s-tab-b')))
li_citys = div_tabs[2].find_elements(By.CSS_SELECTOR ,'a.panel-item')
data = []
#遍历每一个城市
for city in li_citys:
#单击当前城市标签,页面会跳转到该城市下的区县列表
city.click()
#获取区县信息
div_tabs = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'#source-area-select div.s-tab-b')))
li_areas = div_tabs[3].find_elements(By.CSS_SELECTOR ,'a.panel-item')
#遍历每一个区县
for area in li_areas:
data.append(pro.get_attribute('code')+','+pro.get_attribute('panel-item')
+','+city.get_attribute('code')+','+city.get_attribute('panel-item')
+','+area.get_attribute('code')+','+area.get_attribute('panel-item')
+'\n'
)
#跳转回到城市标签,为了遍历下一个城市
click_city()
#将数据写入文件
file.writelines(data)
#跳转回省份标签,为了遍历下一个省份
click_province()
file.close()
browser.quit()
if __name__=='__main__':
main()

Pandas手册(10)- 数据转换

发表于 2017-08-15 | 分类于 Python-Pandas

Python
Pandas


这里接着上一篇,继续记录下pandas中数据处理方面的函数

1. 重复数据

结果集中,可能会有重复数据,有函数可以做去重操作

1
2
3
4
5
6
7
#判断数据是否重复
DataFrame.duplicated(subset=None, keep='first')
Return boolean Series denoting duplicate rows, optionally only considering certain columns
#删除重复记录
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)
Return DataFrame with duplicate rows removed, optionally only considering certain columns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
data = pd.DataFrame({'K1':['one']*3+['two']*4,'k2':[1,1,2,3,3,4,4]})
data
Out[100]:
K1 k2
0 one 1
1 one 1
2 one 2
3 two 3
4 two 3
5 two 4
6 two 4
#keep参数,默认是first,会以第一个为准,后面再出现就是True
data.duplicated()
Out[103]:
0 False
1 True
2 False
3 False
4 True
5 False
6 True
dtype: bool
data.duplicated(keep='last')
Out[116]:
0 True
1 False
2 False
3 True
4 False
5 True
6 False
dtype: bool
#这里drop也是一样的,可以用keep控制保留第一次出现的,还是最后1次出现的
data.drop_duplicates()
Out[104]:
K1 k2
0 one 1
2 one 2
3 two 3
5 two 4

这2个函数,默认都是判断全部的列,也可以指定列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
data['v1']=range(7)
data
Out[118]:
K1 k2 v1
0 one 1 0
1 one 1 1
2 one 2 2
3 two 3 3
4 two 3 4
5 two 4 5
6 two 4 6
data.duplicated()
Out[119]:
0 False
1 False
2 False
3 False
4 False
5 False
6 False
dtype: bool
data.duplicated(subset=['K1'])
Out[120]:
0 False
1 True
2 True
3 False
4 True
5 True
6 True
dtype: bool
data.drop_duplicates(subset=['K1'])
Out[121]:
K1 k2 v1
0 one 1 0
3 two 3 3

2. 利用函数或映射进行数据转换

有的时候,我们想要对Series和dataframe中的每个元素做些转换,就用到了这个函数,和Python内置的map函数类似

1
2
3
4
5
6
Series.map(arg, na_action=None)
Map values of Series using input correspondence (which can be a dict, Series, or function)
arg : function, dict, or Series
DataFrame.applymap(func)
Apply a function to a DataFrame that is intended to operate elementwise, i.e. like doing map(func, series) for each series in the DataFrame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
s1 = pd.Series(range(10))
s1
Out[133]:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
dtype: int32
s1.map(lambda x:x+10)
Out[134]:
0 10
1 11
2 12
3 13
4 14
5 15
6 16
7 17
8 18
9 19
dtype: int64
s1.map(lambda x:x*-1)
Out[135]:
0 0
1 -1
2 -2
3 -3
4 -4
5 -5
6 -6
7 -7
8 -8
9 -9
dtype: int64

这个map,不单单可以是函数,还可以是 Series或dict

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
x = pd.Series([1,2,3], index=['one', 'two', 'three'])
y = pd.Series(['foo', 'bar', 'baz'], index=[1,2,3])
x
Out[142]:
one 1
two 2
three 3
dtype: int64
y
Out[143]:
1 foo
2 bar
3 baz
dtype: object
x.map(y)
Out[144]:
one foo
two bar
three baz
dtype: object
z = {1: 'A', 2: 'B', 3: 'C'}
x.map(z)
Out[146]:
one A
two B
three C
dtype: object

3.替换值

在字符串中,我们经常会用到replace函数,用来替换指定的值,pandas中也有

1
2
3
4
5
6
DataFrame.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad', axis=None)
Replace values given in ‘to_replace’ with ‘value’.
to_replace : str, regex, list, dict, Series, numeric, or None
Series.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad', axis=None)
Replace values given in ‘to_replace’ with ‘value’.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
data = pd.Series([1., -999., 2., -999., -1000., 3.])
data
Out[150]:
0 1.0
1 -999.0
2 2.0
3 -999.0
4 -1000.0
5 3.0
dtype: float64
#我们将-999这个异常值替换掉
data.replace(-999,np.nan)
Out[151]:
0 1.0
1 NaN
2 2.0
3 NaN
4 -1000.0
5 3.0
dtype: float64
#同时替换多个值,也可以
data.replace([-999,-1000],np.nan)
Out[152]:
0 1.0
1 NaN
2 2.0
3 NaN
4 NaN
5 3.0
dtype: float64
data.replace([-999,-1000],[np.nan,0])
Out[153]:
0 1.0
1 NaN
2 2.0
3 NaN
4 0.0
5 3.0
dtype: float64

最新行政区信息获取

发表于 2017-08-14 | 分类于 随笔

这是之前记录的,这里顺便分享下。

之前想要获取官方的省市区的代码code,就找了下。

官方地址:http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/

the-newest-area-info-01-01

我们可以直接将数据复制到Excel中,简单处理下,导入到数据库中

里面会有换行,先去个重,然后trim一下,再分列就可以了

the-newest-area-info-01-02

the-newest-area-info-01-03

最后,我们可以将数据组织成我们想要的维度表格式

————–update at 2017-08-15

上面呢,我是直接在Excel里面生成insert脚本插入数据库的,但是目前的表使用起来应该不是很方便,这里我们改造下。

这个区域信息呢,是很常用的一张维度表,通常他可能会是这个样子的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE base.dm_area
(
area_id integer,
area_name character varying(50),
province_id integer,
province_name character varying(50),
city_id integer,
city_name character varying(50),
country_id integer,
country_name character varying(50),
flevel integer
)
WITH (
OIDS=FALSE
);

这里我们就简单处理下,变成这种格式。

其实一开始的时候,我们可以通过数据的格式区分他是省份、城市、还是区县,下面我们用的是一个套路

主要是观察法,因为这个code都是有规律的,所以我们处理起来方便很多

code一共是6位,前两位是省份、中间2位是城市,后2位是区县

1
select *from public.b_area where area_id||'' like '00'

the-newest-area-info-01-04

下面,我们来初始化数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
INSERT INTO base.dm_area(
area_id, area_name)
select *from public.b_area;
-- 初始化flevel 1:省份,2:城市,3:区县
update base.dm_area set flevel=1 where area_id||'' like '00';
update base.dm_area set flevel=2 where area_id||'' like '' and flevel is null;
update base.dm_area set flevel=3 where flevel is null;
-- 更新省份信息
update base.dm_area a
set
province_id = b.area_id,
province_name = b.area_name
from
base.dm_area b
where
left(a.area_id||'',2)=left(b.area_id||'',2) and b.flevel=1;
-- 更新城市信息
update base.dm_area a
set
city_id = c.area_id,
city_name = c.area_name
from
base.dm_area c
where
left(a.area_id||'',4)=left(c.area_id||'',4) and c.flevel=2;
-- 更新区县信息
update base.dm_area a
set
country_id = area_id,
country_name = area_name
where
a.flevel=3;

到这里,flevel=3的数据已经没有问题了,再对省份、城市做些优化就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 补全数据
update base.dm_area
set
city_id=-area_id,city_name=area_name||'XT',
country_id=-area_id,country_name=area_name||'XT'
where
flevel=1;
update base.dm_area
set
country_id=-area_id,country_name=area_name||'XT'
where
flevel=2;

the-newest-area-info-01-05

好了,我们就处理好这个区域维度了,正常使用的话,估计就用flevel=3的就够了

1…101112…23
于贵洋

于贵洋

111 日志
17 分类
30 标签
RSS
GitHub
友情链接
  • 很久之前的CSDN博客
0%
© 2017 于贵洋
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.3
Hosted by GitHub Pages
本站访客数 人次 本站总访问量 次