数据合并之join:
join:默认情况下他是把行索引相同的数据合并到一起
In [6]: t1 = pd.DataFrame(np.zeros((2,5)),index=["A","B"],columns=list("VWXYZ"))
In [7]: t1
Out[7]:
V W X Y Z
A 0.0 0.0 0.0 0.0 0.0
B 0.0 0.0 0.0 0.0 0.0
In [8]: t2 = pd.DataFrame(np.ones((3,4)),index=list("ABC"),columns=list("0123"))
In [9]: t2
Out[9]:
0 1 2 3
A 1.0 1.0 1.0 1.0
B 1.0 1.0 1.0 1.0
C 1.0 1.0 1.0 1.0
In [10]: t1.join(t2)
Out[10]:
V W X Y Z 0 1 2 3
A 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
B 0.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
In [11]: t2.join(t1)
Out[11]:
0 1 2 3 V W X Y Z
A 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0
B 1.0 1.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0
C 1.0 1.0 1.0 1.0 NaN NaN NaN NaN NaN
可以看到join是将index相同的行进行了合并,以左操作数为基础进行合并
数据合并之merge:
In [25]: t1
Out[25]:
V W X Y Z
A 0.0 0.0 c 0.0 0.0
B 0.0 0.0 d 0.0 0.0
In [26]: t2
Out[26]:
M N P Q O
A 1.0 1.0 1.0 1.0 a
B 1.0 1.0 1.0 1.0 b
C 1.0 1.0 1.0 1.0 c
In [27]: t1.merge(t2,left_on="X",right_on="O") # 默认的合并方式inner,交集
Out[27]:
V W X Y Z M N P Q O
0 0.0 0.0 c 0.0 0.0 1.0 1.0 1.0 1.0 c
In [28]: t1.merge(t2,left_on="X",right_on="O",how="inner") # 内连接
Out[28]:
V W X Y Z M N P Q O
0 0.0 0.0 c 0.0 0.0 1.0 1.0 1.0 1.0 c
In [29]: t1.merge(t2,left_on="X",right_on="O",how="outer") # 外连接 merge outer,并集,NaN补全
Out[29]:
V W X Y Z M N P Q O
0 0.0 0.0 c 0.0 0.0 1.0 1.0 1.0 1.0 c
1 0.0 0.0 d 0.0 0.0 NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN 1.0 1.0 1.0 1.0 a
3 NaN NaN NaN NaN NaN 1.0 1.0 1.0 1.0 b
In [30]: t1.merge(t2,left_on="X",right_on="O",how="left") # 左连接 merge left,左边为准,NaN补全
Out[30]:
V W X Y Z M N P Q O
0 0.0 0.0 c 0.0 0.0 1.0 1.0 1.0 1.0 c
1 0.0 0.0 d 0.0 0.0 NaN NaN NaN NaN NaN
In [31]: t1.merge(t2,left_on="X",right_on="O",how="right") # 右连接 merge right,右边为准,NaN补全
Out[31]:
V W X Y Z M N P Q O
0 NaN NaN NaN NaN NaN 1.0 1.0 1.0 1.0 a
1 NaN NaN NaN NaN NaN 1.0 1.0 1.0 1.0 b
2 0.0 0.0 c 0.0 0.0 1.0 1.0 1.0 1.0 c
可以看到merge是以指定的columns对应的两个列中元素相同的连接为一行
例题:
- 现在我们有一组关于全球星巴克店铺的统计数据,如果我想知道美国的星巴克数量和中国的哪个多,或者我想知道中国每个省份星巴克的数量的情况,那么应该怎么办?
- 要统计美国和中国的星巴克的数量,我们应该怎么做?
- 数据来源:https://www.kaggle.com/starbucks/store-locations/data
- 数据格式:
Brand Store Number Store Name Ownership Type Street Address City State/Province Country Postcode Phone Number Timezone Longitude Latitude
Starbucks 47370-257954 Meritxell, 96 Licensed Av. Meritxell, 96 Andorra la Vella 7 AD AD500 376818720 GMT+1:00 Europe/Andorra 1.53 42.51
Starbucks 22331-212325 Ajman Drive Thru Licensed 1 Street 69, Al Jarf Ajman AJ AE GMT+04:00 Asia/Dubai 55.47 25.42
Starbucks 47089-256771 Dana Mall Licensed Sheikh Khalifa Bin Zayed St. Ajman AJ AE GMT+04:00 Asia/Dubai 55.47 25.39
代码:
import pandas as pd
df = pd.read_csv("./starbucks_store_worldwide.csv")
# print(df.info())
# print(df.head(1))
# 按照国家进行分组(聚合)
country_info = df.groupby(by="Country")
# 遍历输出分组后的信息
for i,j in country_info:
print("-"*50)
print(i)
print("*"*50)
print(j)
# 计算分组后每一个国家牌子的数量
country_num = country_info["Brand"].count()
print(country_num)
df[df["Country"]=="US"]
# 分别输出美国和中国的星巴克Brand的数量
print(country_num["US"])
print(country_num["CN"])
# 统计中国每个省店铺的数量
china_data = df[df["Country"] == "CN"]
# 按照省分组
grouped = china_data.groupby(by="State/Province").count()["Brand"]
print(grouped)
# 将数据按照多个条件分组
grouped = df["Brand"].groupby(by=[df["Country"],df["State/Province"]]).count()
print(grouped)
print(type(grouped))
# 按多条件进行分组,返回DataFrame
grouped1 = df[["Brand"]].groupby(by=[df["Country"],df["State/Province"]]).count()
grouped2 = df.groupby(by=[df["Country"],df["State/Province"]]).count()[["Brand"]]
grouped3 = df.groupby(by=[df["Country"],df["State/Province"]])[["Brand"]].count()
print(grouped1,type(grouped1)) # <class 'pandas.core.frame.DataFrame'>
print("*"*50)
print(grouped2,type(grouped2)) # <class 'pandas.core.frame.DataFrame'>
print("*"*50)
print(grouped3,type(grouped3)) # <class 'pandas.core.frame.DataFrame'>
分组和聚合:
在pandas中类似的分组的操作我们有很简单的方式来完成
df.groupby(by="columns_name")
grouped = df.groupby(by="columns_name")
grouped是一个DataFrameGroupBy对象,是可迭代的
grouped中的每一个元素是一个元组
元组里面是(索引(分组的值),分组之后的DataFrame)
如果我们需要对国家和省份进行分组统计,应该怎么操作呢?
grouped = df.groupby(by=[df["Country"],df["State/Province"]])
很多时候我们只希望对获取分组之后的某一部分数据,或者说我们只希望对某几列数据进行分组,这个时候我们应该怎么办呢?
获取分组之后的某一部分数据:
df.groupby(by=["Country","State/Province"])["Country"].count()
对某几列数据进行分组:
df["Country"].groupby(by=[df["Country"],df["State/Province"]]).count()
观察结果,由于只选择了一列数据,所以结果是一个Series类型
t1 = df[["Country"]].groupby(by=[df["Country"],df["State/Province"]]).count()t2 = df.groupby(by=["Country","State/Province"])[["Country"]].count()
以上的两条命令结果一样
和之前的结果的区别在于当前返回的是一个DataFrame类型.
DataFrameGroupBy对象有很多经过优化的方法:
函数名 说明
count 分组中非NA值的数量
sum 非NA值的和
mean 非NA值的平均值
median 非NA值的算术中位数
std、var 无偏(分母为n-1)标准差和方差
min、max 非NA值的最小值和最大值
索引和复合索引:
简单的索引操作:
获取index: df.index
指定index: df.index = ['x','y']
重新设置index: df.reindex(list("abcedf")) # 新的index对应的值都为NaN
指定某一列作为index: df.set_index("Country",drop=False) # drop为False时在数据中保留原来的列
返回index的唯一值: df.set_index("Country").index.unique()
假设a为一个DataFrame,那么当a.set_index(["c","d"])即设置两个索引的时候是什么样子的结果呢?
a = pd.DataFrame({'a': range(7),'b': range(7, 0, -1),'c': ['one','one','one','two','two','two', 'two'],'d': list("hjklmno")})
Series复合索引:
In [52]: a
Out[52]:
a b c d
0 0 7 one h
1 1 6 one j
2 2 5 one k
3 3 4 two l
4 4 3 two m
5 5 2 two n
6 6 1 two o
In [53]: X = a.set_index(["c","d"])["a"]
In [54]: X
Out[54]:
c d
one h 0
j 1
k 2
two l 3
m 4
n 5
o 6
Name: a, dtype: int64
In [55]: X["one","h"] # Series符合索引取值,直接在括号里面写索引就行
Out[55]: 0
In [10]: type(X)
Out[10]: pandas.core.series.Series
In [11]: X.swaplevel() # 交换索引的里外层
Out[11]:
d c
h one 0
j one 1
k one 2
l two 3
m two 4
n two 5
o two 6
Name: a, dtype: int64
In [12]: X.swaplevel()["h"] # 此时可以直接取"h"索引
Out[12]:
c
one 0
Name: a, dtype: int64
In [13]: X.index.levels
Out[13]: FrozenList([['one', 'two'], ['h', 'j', 'k', 'l', 'm', 'n', 'o']])
In [14]: X.swaplevel().index.levels
Out[14]: FrozenList([['h', 'j', 'k', 'l', 'm', 'n', 'o'], ['one', 'two']])
In [18]: a
Out[18]:
a b c d
0 0 7 one h
1 1 6 one j
2 2 5 one k
3 3 4 two l
4 4 3 two m
5 5 2 two n
6 6 1 two o
In [19]: x = a.set_index(["c","d"])[["a"]] # pandas.core.frame.DataFrame
In [20]: x
Out[20]:
a
c d
one h 0
j 1
k 2
two l 3
m 4
n 5
o 6
In [21]: x.loc["one"]
Out[21]:
a
d
h 0
j 1
k 2
In [22]: x.loc["one"].loc["h"]
Out[22]:
a 0
Name: h, dtype: int64
根据上个例题的数据:
- 使用matplotlib呈现出店铺总数排名前10的国家
- 使用matplotlib呈现出中国每个城市的店铺数量
代码1:
import pandas as pd
from matplotlib import pyplot as plt
# 准备数据
df = pd.read_csv("./starbucks_store_worldwide.csv")
# 提取数据
country_data = df.groupby(by="Country")["Brand"].count().sort_values(ascending=False)[:10]
# 设置图片大小
plt.figure(figsize=(20,8),dpi=80)
# 画条型图
plt.bar(range(len(country_data)),country_data,width=0.4,color="pink")
# 设置x刻度
plt.xticks(range(len(country_data)),country_data.index)
# 显示图片
plt.show()
效果图:
代码2:
import pandas as pd
from matplotlib import pyplot as plt
import matplotlib
font = {'family' : 'WenQuanYi Micro Hei',
'weight' : 'bold',
'size' : '10'}
# 设置中文字体
matplotlib.rc("font",**font)
# 准备数据
df = pd.read_csv("./starbucks_store_worldwide.csv")
print(df.info())
# 提取数据
df = df[df["Country"]=="CN"]
china_data = df.groupby(by="City")["Brand"].count().sort_values(ascending=False)[:25]
print(china_data)
# 设置图片大小
plt.figure(figsize=(20,8),dpi=80)
# 绘制直方图
plt.bar(range(25),china_data.values,width=0.4,color="green")
# 设置x刻度
plt.xticks(range(25),china_data.index)
# 显示图片
plt.show()
效果图:
例题:
现在我们有全球排名靠前的10000本书的数据,那么请统计一下下面几个问题:
- 不同年份书的数量
- 不同年份书的平均评分情况
收据来源:https://www.kaggle.com/zygmunt/goodbooks-10k
数据格式:
代码:
import pandas as pd
from matplotlib import pyplot as plt
# 准备数据
df = pd.read_csv("./books.csv")
# print(df.info())
# print(df.head(1))
# 去除空数据所在行
# df = df[pd.notnull(df["original_publication_year"])]
# 提取数据
# data_book_count = df.groupby(by="original_publication_year").count()["title"]
data_book_avg = df["average_rating"].groupby(by=df["original_publication_year"]).mean()
_x = data_book_avg.index
_y = data_book_avg.values
# 设置图片大小
plt.figure(figsize=(20,8),dpi=80)
# 画折线图
plt.plot(range(len(_x)),_y)
# 设置x刻度
plt.xticks(list(range(len(_x)))[::10],_x[::10],rotation=45)
# 显示
plt.show()
效果图: