pandas.DataFrame的pivot()和unstack()實(shí)現(xiàn)行轉(zhuǎn)列
示例:有如下表需要進(jìn)行行轉(zhuǎn)列:

代碼如下:
# -*- coding:utf-8 -*-
import pandas as pd
import MySQLdb
from warnings import filterwarnings
# 由于create table if not exists總會(huì)拋出warning,因此使用filterwarnings消除
filterwarnings('ignore', category = MySQLdb.Warning)
from sqlalchemy import create_engine
import sys
if sys.version_info.major<3:
reload(sys)
sys.setdefaultencoding("utf-8")
# 此腳本適用于python2和python3
host,port,user,passwd,db,charset="192.168.1.193",3306,"leo","mysql","test","utf8"
def get_df():
global host,port,user,passwd,db,charset
conn_config={"host":host, "port":port, "user":user, "passwd":passwd, "db":db,"charset":charset}
conn = MySQLdb.connect(**conn_config)
result_df=pd.read_sql('select UserName,Subject,Score from TEST',conn)
return result_df
def pivot(result_df):
df_pivoted_init=result_df.pivot('UserName','Subject','Score')
df_pivoted = df_pivoted_init.reset_index() # 將行索引也作為DataFrame值的一部分,以方便存儲(chǔ)數(shù)據(jù)庫
return df_pivoted_init,df_pivoted
# 返回的兩個(gè)DataFrame,一個(gè)是以姓名作index的,一個(gè)是以數(shù)字序列作index,前者用于unpivot,后者用于save_to_mysql
def unpivot(df_pivoted_init):
# unpivot需要進(jìn)行df_pivoted_init二維表格的行、列索引遍歷,需要拼SQL因此不能使用save_to_mysql存數(shù)據(jù),這里使用SQL和MySQLdb接口存
insert_sql="insert into test_unpivot(UserName,Subject,Score) values "
# 處理值為NaN的情況
df_pivoted_init=df_pivoted_init.fillna(0)
for col in df_pivoted_init.columns:
for index in df_pivoted_init.index:
value=df_pivoted_init.at[index,col]
if value!=0:
insert_sql=insert_sql+"('%s','%s',%s)" %(index,col,value)+','
insert_sql = insert_sql.strip(',')
global host, port, user, passwd, db, charset
conn_config = {"host": host, "port": port, "user": user, "passwd": passwd, "db": db, "charset": charset}
conn = MySQLdb.connect(**conn_config)
cur=conn.cursor()
cur.execute("create table if not exists test_unpivot like TEST")
cur.execute(insert_sql)
conn.commit()
conn.close()
def save_to_mysql(df_pivoted,tablename):
global host, port, user, passwd, db, charset
"""
只有使用sqllite時(shí)才能指定con=connection實(shí)例,其他數(shù)據(jù)庫需要使用sqlalchemy生成engine,engine的定義可以添加?來設(shè)置字符集和其他屬性
"""
conn="mysql://%s:%s@%s:%d/%s?charset=%s" %(user,passwd,host,port,db,charset)
mysql_engine = create_engine(conn)
df_pivoted.to_sql(name=tablename, con=mysql_engine, if_exists='replace', index=False)
# 從TEST表讀取源數(shù)據(jù)至DataFrame結(jié)構(gòu)
result_df=get_df()
# 將源數(shù)據(jù)行轉(zhuǎn)列為二維表格形式
df_pivoted_init,df_pivoted=pivot(result_df)
# 將二維表格形式的數(shù)據(jù)存到新表test中
save_to_mysql(df_pivoted,'test')
# 將被行轉(zhuǎn)列的數(shù)據(jù)unpivot,存入test_unpivot表中
unpivot(df_pivoted_init)
結(jié)果如下:

關(guān)于Pandas DataFrame類自帶的pivot方法:
DataFrame.pivot(index=None, columns=None, values=None):
Return reshaped DataFrame organized by given index / column values.
這里只有3個(gè)參數(shù),是因?yàn)閜ivot之后的結(jié)果一定是二維表格,只需要行列及其對(duì)應(yīng)的值,而且也因?yàn)槭嵌S表格,unpivot之后is_pass列是肯定會(huì)丟失的,因此一開始我就沒查這個(gè)列。
補(bǔ)充說明:
在學(xué)習(xí)到Pandas的層次化索引部分時(shí)發(fā)現(xiàn)了2個(gè)很有意思的函數(shù),也可以進(jìn)行行列互轉(zhuǎn),其用法如下:(很久之后我才意識(shí)到,pivot只是封裝了unstack的一個(gè)快捷方式而已,其本質(zhì)上還是先用set_index建立層次化索引,然后用unstack進(jìn)行重塑,就像我在下面示例做的操作)
# -*- coding:utf-8 -*-
import pandas as pd
import MySQLdb
from warnings import filterwarnings
# 由于create table if not exists總會(huì)拋出warning,因此使用filterwarnings消除
filterwarnings('ignore', category = MySQLdb.Warning)
from sqlalchemy import create_engine
import sys
if sys.version_info.major<3:
reload(sys)
sys.setdefaultencoding("utf-8")
# 此腳本適用于python2和python3
host,port,user,passwd,db,charset="192.168.1.193",3306,"leo","mysql","test","utf8"
def get_df():
global host,port,user,passwd,db,charset
conn_config={"host":host, "port":port, "user":user, "passwd":passwd, "db":db,"charset":charset}
conn = MySQLdb.connect(**conn_config)
result_df=pd.read_sql('select UserName,Subject,Score from TEST',conn)
return result_df
def pivot(result_df):
df_pivoted_init=result_df.pivot('UserName','Subject','Score')
df_pivoted = df_pivoted_init.reset_index() # 將行索引也作為DataFrame值的一部分,以方便存儲(chǔ)數(shù)據(jù)庫
return df_pivoted_init,df_pivoted
# 返回的兩個(gè)DataFrame,一個(gè)是以姓名作index的,一個(gè)是以數(shù)字序列作index,前者用于unpivot,后者用于save_to_mysql
def unpivot(df_pivoted_init):
# unpivot需要進(jìn)行df_pivoted_init二維表格的行、列索引遍歷,需要拼SQL因此不能使用save_to_mysql存數(shù)據(jù),這里使用SQL和MySQLdb接口存
insert_sql="insert into test_unpivot(UserName,Subject,Score) values "
# 處理值為NaN的情況
df_pivoted_init=df_pivoted_init.fillna(0)
for col in df_pivoted_init.columns:
for index in df_pivoted_init.index:
value=df_pivoted_init.at[index,col]
if value!=0:
insert_sql=insert_sql+"('%s','%s',%s)" %(index,col,value)+','
insert_sql = insert_sql.strip(',')
global host, port, user, passwd, db, charset
conn_config = {"host": host, "port": port, "user": user, "passwd": passwd, "db": db, "charset": charset}
conn = MySQLdb.connect(**conn_config)
cur=conn.cursor()
cur.execute("create table if not exists test_unpivot like TEST")
cur.execute(insert_sql)
conn.commit()
conn.close()
def save_to_mysql(df_pivoted,tablename):
global host, port, user, passwd, db, charset
"""
只有使用sqllite時(shí)才能指定con=connection實(shí)例,其他數(shù)據(jù)庫需要使用sqlalchemy生成engine,engine的定義可以添加?來設(shè)置字符集和其他屬性
"""
conn="mysql://%s:%s@%s:%d/%s?charset=%s" %(user,passwd,host,port,db,charset)
mysql_engine = create_engine(conn)
df_pivoted.to_sql(name=tablename, con=mysql_engine, if_exists='replace', index=False)
# 從TEST表讀取源數(shù)據(jù)至DataFrame結(jié)構(gòu)
result_df=get_df()
# 將源數(shù)據(jù)行轉(zhuǎn)列為二維表格形式
df_pivoted_init,df_pivoted=pivot(result_df)
# 將二維表格形式的數(shù)據(jù)存到新表test中
save_to_mysql(df_pivoted,'test')
# 將被行轉(zhuǎn)列的數(shù)據(jù)unpivot,存入test_unpivot表中
unpivot(df_pivoted_init)
以上利用了Pandas的層次化索引,實(shí)際上這也是層次化索引一個(gè)主要的用途,結(jié)合本例我們可以把代碼改成如下:
result_df=pd.read_sql('select UserName,Subject,Score from TEST',conn)
# 在從數(shù)據(jù)庫中獲取的數(shù)據(jù)格式是這樣的:
UserName Subject Score
0 張三 語文 80.0
1 張三 數(shù)學(xué) 90.0
2 張三 英語 70.0
3 張三 生物 85.0
4 李四 語文 80.0
5 李四 數(shù)學(xué) 92.0
6 李四 英語 76.0
7 王五 語文 60.0
8 王五 數(shù)學(xué) 82.0
9 王五 英語 96.0
10 王五 生物 78.0
# 如果要使用層次化索引,那么我們只需要把UserName和Subject列設(shè)置為層次化索引,Score為其對(duì)應(yīng)的值即可,我們借用set_index()函數(shù):
df=result_df.set_index(['UserName','Subject'])
In [112]: df.unstack()
Out[112]:
Score
Subject 數(shù)學(xué) 生物 英語 語文
UserName
張三 90.0 85.0 70.0 80.0
李四 92.0 NaN 76.0 80.0
王五 82.0 78.0 96.0 60.0
# 使用stack可以將unstack的結(jié)果轉(zhuǎn)回來,這樣就也在形式上實(shí)現(xiàn)了行列互轉(zhuǎn),之后的操作基本一致了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python多線程中阻塞(join)與鎖(Lock)使用誤區(qū)解析
這篇文章主要為大家詳細(xì)介紹了Python多線程中阻塞join與鎖Lock的使用誤區(qū),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
python實(shí)現(xiàn)簡(jiǎn)單的俄羅斯方塊
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡(jiǎn)單的俄羅斯方塊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
django 實(shí)現(xiàn)編寫控制登錄和訪問權(quán)限控制的中間件方法
今天小編就為大家分享一篇django 實(shí)現(xiàn)編寫控制登錄和訪問權(quán)限控制的中間件方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01
python的staticmethod與classmethod實(shí)現(xiàn)實(shí)例代碼
這篇文章主要介紹了python的staticmethod與classmethod實(shí)現(xiàn)實(shí)例代碼,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02
用python實(shí)現(xiàn)英文字母和相應(yīng)序數(shù)轉(zhuǎn)換的方法
這篇文章主要介紹了用python實(shí)現(xiàn)英文字母和相應(yīng)序數(shù)轉(zhuǎn)換的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
對(duì)于Python的框架中一些會(huì)話程序的管理
這篇文章主要介紹了對(duì)于Python的框架中一些會(huì)話程序的管理,會(huì)話的實(shí)現(xiàn)是Python框架的基本功能,本文主要講述了對(duì)其的一些管理維護(hù)要點(diǎn),需要的朋友可以參考下2015-04-04

