Pandas數據處理筆記_Markdown版

引言:自從熟練了Markdown的語法後,寫啥文檔都好方便啊~一發不可收拾了.這兩天又用到了pandas,翻出來之前做的筆記添加新內容的時候明顯感覺很難受啊有木有,奈何CSDN也沒有提供富文本編輯器生成的老博文直接轉Markdown的功能,只好再一段一段的手工改一遍吧,之前那篇筆記就存檔了,不再更新.以後都在這個裏面追加記錄新知識. -2019.11.12

讀取CSV/Excel文件指定數據類型

import numpy as np

df = pd.read_csv('xxx.csv', encoding='gbk', dtype='str') # 指定每列數據都爲str
df = pd.read_csv('xxx.csv', encoding='gbk', dtype={'b': object, 'c': np.float64}) # 指定b列爲字符串類型,c列爲float64類型

df = pd.read_excel('xxx.xls', encoding='gbk', dtype='str') # xls格式讀取

dtype常用類型(使用numpy庫提供的對象類型):

str 字符串
int64 整數
float64 浮點小數

修改DataFrame對象中列的數據類型

# 將df對象中的id列數據類型修改爲字符串str類型
df['id'] = df['id'].astype(str)

# 使用字典映射{列:數據類型}實現批量修改多列數據類型
convert_dict = {
	'id': str,
	'value': float
	'value2': int
}
df = df.astype(convert_dict)

# 使用.apply和pd.to_numeric實現批量修改多列數據類型
df[['A', 'B', 'C']] = df[['A', 'B', 'C']].apply(pd.to_numeric)

# 對所有列批量轉數字類型,自動判斷int還是float,遇到非數字內容列則不轉換
df = df.apply(lambda x:pd.to_numeric(x, errors='ignore'))

to_numeric() 中的errors參數效果:

  • 'raise' 轉換失敗拋出異常,程序中斷
  • 'ignore' 轉換失敗會忽略不做修改,返回原來的數據類型
  • 'coerce' 轉換失敗會返回NaN

只對數字列進行sum彙總

df.sum(numeric_only=True)

對單個xlsx文件中全部工作簿進行合併

在一個xlsx文件中存在多個worksheet,其中的數據格式一致,將所有worksheet進行拼接合並,並導出csv

方法一:使用read_excel

import pandas as pd
df = pd.read_excel('xxx.xlsx', sheet_name=None, ignore_index=True)    #這裏注意要帶上後面的兩個參數,否則會只加載第一個工作簿的數據
cdf = pd.concat(df.values())
cdf.to_csv('new.csv')

方法二:使用ExcelFile.pares

import pandas as pd

file = pd.ExcelFile('0629.xls')
print(file.sheet_names)
df = []
for sheet in file.sheet_names:
    df.append(file.parse(sheet))

cdf = pd.concat(df)
cdf.to_csv('concat.csv')
print('Job Done')

將DataFrame導出文件

df.to_excel('aaa.xlsx')    # 需要xlwt包的支持,用之前pip install xlwt一下,導出xlsx格式速度會比較慢,數據量大的時候不推薦
df.to_csv('bbb.csv', index=False, encoding='gb2312')    # index=False指定導出的文件中不帶數據行號列,encoding指定文件編碼,win下面必須指定gb2312,否則excel打開中文亂碼

對DataFrame中的數據進行分類,然後獲取每一分類的前n條

grouped = df.groupby(['class']).head(2)

使用列名對DataFrame進行數據選取

df[col]  #根據列名,並以Series的形式返回列
df[[col1, col2]]  #以DataFrame形式返回多列

使用iloc對DataFrame進行數據選取

# Single selections using iloc and DataFrame
# Rows:
data.iloc[0] # first row of data frame (Aleshia Tomkiewicz) - Note a Series data type output.
data.iloc[1] # second row of data frame (Evan Zigomalas)
data.iloc[-1] # last row of data frame (Mi Richan)
# Columns:
data.iloc[:,0] # first column of data frame (first_name)
data.iloc[:,1] # second column of data frame (last_name)
data.iloc[:,-1] # last column of data frame (id)

DataFrame保留小數點兩位

df = df.round(2)

判斷數據是否爲NaN

# 判斷name列是否爲NaN空值
pd.isna(df['name'])

按條件修改數據

# 對df中name列='Dexter'的行對應的name列數據修改爲'Tom'
df.loc[df['name']=='Dexter', 'name'] = 'Tom'

修改DataFrame中列的數據類型

查看DataFrame對象每個列的當前數據類型

df.dtypes

修改列的數據類型

df_obj['列名'].astype(int)
df_obj['列名'].astype(float)

批量修改多個列的數據類型

B204_cols = ['col1', 'col2', 'col3']
df[B204_cols] = df[B204_cols].apply(pd.to_numeric, errors='coerce')

實現SQL中distinct查詢

df['列1'].unique()

刪除指定列

df.drop(columns=['A', 'B'], axis=1, inplace=True)

# axis=1 表明刪除列

# inplace=True 表明對df直接對象進行修改

根據條件進行數據篩選

df[df[col] > 0.5]  # 選擇col列的值大於0.5的行
df[df.iloc[:,15]=='xxx']  # 選擇第15列(列標從0開始)等於xxx的行
df[(df[col1] > 0.5) & (df[col2] > 1)]    # 多條件篩選

查看DataFrame對象數據總行數

len(df)

Series類型對象合併兩列數據

在這裏插入圖片描述
Series A和B進行合併計算

s1.combine_first(s2)

DataFrame相減處理(集合處理,不是數據減法計算)

How to remove a pandas dataframe from another dataframe, just like the set subtraction:

a=[1,2,3,4,5]
b=[1,5]
a-b=[2,3,4]

And now we have two pandas dataframe, how to remove df2 from df1:

In [5]: df1=pd.DataFrame([[1,2],[3,4],[5,6]],columns=['a','b'])
In [6]: df1
Out[6]:
   a  b
0  1  2
1  3  4
2  5  6

In [9]: df2=pd.DataFrame([[1,2],[5,6]],columns=['a','b'])
In [10]: df2
Out[10]:
   a  b
0  1  2
1  5  6

Then we expect df1-df2 result will be:

In [14]: df
Out[14]:
   a  b
0  3  4

Use pd.concat followed by drop_duplicates(keep=False)

pd.concat([df1, df2, df2]).drop_duplicates(keep=False)

It looks like

   a  b
1  3  4

續接兩個Series對象

s1 = pd.Series([1,2,3])
s2 = pd.Series([2,5,6,7,8])
s = s1.append(s2)
# s:[1,2,3,2,5,6,7,8]

統計查看DataFrame/Series重複數據

例如上面的拼接後的s對象,其中的數值2是存在重複的,那麼要查看的話這樣操作:

>>> s
0    1
1    2
2    3
0    2
1    5
2    6
3    7
4    8
dtype: int64
>>> s.duplicated()    # 查看重複情況,不過這個結果看起來很不友好的,主要是用於獲得重複數據的bool結果
0    False
1    False
2    False
0     True
1    False
2    False
3    False
4    False
dtype: bool
>>> s[s.duplicated()]    # 查看重複的具體數據
0    2
dtype: int64
>>> s[s.duplicated()].count()    # 統計重複數據數量
1
>>> s[s.duplicated(keep=False)]    # 加上參數keep=False,效果是隻保留所有重複的數據

Series轉DataFrame類型

Series對象就是一個一維數組而已,是沒有列名屬性的,轉換成DataFrame對象加上列名

s.to_frame('列名')

根據指定列對兩個DataFrame進行相減處理去除重複行

有兩個DataFrame對象df1是完整數據,df2是一個Series轉換過來的DataFrame對象,其實就一列,現在想從df1中找出所有電話列=df2中數據的行刪除掉,得到期望結果
在這裏插入圖片描述

result = pd.concat([df1,df2], ignore_index=True, sort=False).drop_duplicates(subset='電話', keep=False)

對DataFrame分組後再隨機抽取行

按照‘鄉鎮’列進行分組,然後每一組裏面隨機抽取500行數據

import pandas as pd
rnd_size = 500  #隨機抽取樣本數量
df = pd.read_csv('cmcc_all.csv')
result = df.groupby('鄉鎮').apply(lambda x: x.sample(rnd_size))
result.to_csv('隨機抽取結果.csv')
print('導出完成')

分組統計

對下面這張表按縣區進行分組,然後統計問題1~問題4各有多少個(計數)

縣區 問題1 問題2 問題3 問題4
湯陰 1 1 0 1
內黃 0 0 1
湯陰 1 0 0 1
湯陰 0 0 1
>>> df
   縣區  問題1  問題2  問題3  問題4
0  湯陰    1    1    0  1.0
1  內黃    0    0    1  NaN
2  湯陰    1    0    0  1.0
3  湯陰    0    0    1  NaN
>>> gp = df.groupby('縣區').count()
>>> gp
    問題1  問題2  問題3  問題4
縣區
內黃    1    1    1    0
湯陰    3    3    3    2
>>> gp = df.groupby('縣區').sum()
>>> gp
    問題1  問題2  問題3  問題4
縣區
內黃    0    0    1  0.0
湯陰    2    1    1  2.0

計數結果:

縣區 問題1 問題2 問題3 問題4
內黃 1 1 1 0
湯陰 3 3 3 2

實現Excel中Vlookup效果

在這裏插入圖片描述
將df1和df2的A列進行關聯查詢,得到result中的結果

>>> df1 = pd.DataFrame(columns=['A', 'B'], data=[[10,'Tom'],[11,'Kate'],[12,'Jack'],[13,'Claire']])
>>> df1
    A       B
0  10     Tom
1  11    Kate
2  12    Jack
3  13  Claire
>>> df2 = pd.DataFrame(columns=['A', 'C'], data=[[9,'Good'],[10,'Bad'],[11,'Good'],[12,'Bad'],[13,'Bad']])
>>> df2
    A     C
0   9  Good
1  10   Bad
2  11  Good
3  12   Bad
4  13   Bad
>>> result = df1.merge(df2, on='A', how='left')
>>> result
    A       B     C
0  10     Tom   Bad
1  11    Kate  Good
2  12    Jack   Bad
3  13  Claire   Bad

數據透視圖之堆疊(stack)分組統計實例

有這樣的原始數據:

xz q1 q2 q3
內黃 A B B
湯陰 A B B
水冶 B A A
滑縣 A B A
滑縣 C C C
滑縣 C C C
水冶 A A B

期望效果:以xz爲index,index,分別對q1,q2,q3中可能出現的數據結果進行分列進行計數統計
在這裏插入圖片描述

>>> df = pd.read_excel('test.xlsx',sheet_name=1)    # 數據放在test.xlsx第二個工作簿裏面,故指定sheet_name=1(從0開始)
>>> df
   xz q1 q2 q3
0  內黃  A  B  B
1  湯陰  A  B  B
2  水冶  B  A  A
3  滑縣  A  B  A
4  滑縣  C  C  C
5  滑縣  C  C  C
6  水冶  A  A  B

>>> result = (df.set_index('xz')).groupby(level='xz').apply(lambda x: x.apply(pd.value_counts)).unstack(level=1).fillna(0)

# 分行解釋一下:
>>> result = (df.set_index('xz'))\    # 先設置index使用xz列
    .groupby(level='xz')\    # 以xz分組
    .apply(lambda x: x.apply(pd.value_counts))\    # 使用匿名函數lambda對數值進行計數統計
    .unstack(level=1)\    # 設置不堆疊
    .fillna(0)    # 對空置用0填充

>>> result.to_excel('result.xlsx')

上面的方法可以實現效果,但是如果q1~q3中可能存在的值不是都一樣是A,B,C這三種情況的話,比如說q1可能的值是A,B,C,而q2可能的值是X,Y,Z
這樣的話上述方法出來的結果就不對了,得用下面這種方法來構造,從stack overflow上面看的,具體每一步的解釋沒完全看懂,但是管用
原貼地址(https://stackoverflow.com/questions/44165629/pandas-pivot-table-for-multiple-columns-at-once)

這種情況:

xz q1 q2 q3
內黃 A X B
湯陰 A X B
水冶 B Y A
滑縣 A Z A
滑縣 C Y C
滑縣 C X C
水冶 A Y B
# 如果還用剛纔的方法來做的話,會把q1~q3中每一種可能出現的值都算成一列,就是這樣:

>>> result = (df.set_index('xz')).groupby(level='xz').apply(lambda x: x.apply(pd.value_counts)).unstack(level=1)

>>> result
     q1                        q2                          q3
      A    B    C   X   Y   Z   A   B   C    X    Y    Z    A    B    C   X   Y   Z
xz
內黃  1.0  NaN  NaN NaN NaN NaN NaN NaN NaN  1.0  NaN  NaN  NaN  1.0  NaN NaN NaN NaN
水冶  1.0  1.0  NaN NaN NaN NaN NaN NaN NaN  NaN  2.0  NaN  1.0  1.0  NaN NaN NaN NaN
湯陰  1.0  NaN  NaN NaN NaN NaN NaN NaN NaN  1.0  NaN  NaN  NaN  1.0  NaN NaN NaN NaN
滑縣  1.0  NaN  2.0 NaN NaN NaN NaN NaN NaN  1.0  1.0  1.0  1.0  NaN  2.0 NaN NaN NaN

# 所以應該用下面的方法來實現

>>> a = df.set_index('xz').stack().groupby(level=[0,1]).value_counts().unstack(level=[1,2]).sort_index(axis=1)

>>> a
     q1             q2             q3
      A    B    C    X    Y    Z    A    B    C
xz
內黃  1.0  NaN  NaN  1.0  NaN  NaN  NaN  1.0  NaN
水冶  1.0  1.0  NaN  NaN  2.0  NaN  1.0  1.0  NaN
湯陰  1.0  NaN  NaN  1.0  NaN  NaN  NaN  1.0  NaN
滑縣  1.0  NaN  2.0  1.0  1.0  1.0  1.0  NaN  2.0

對上面例子中的多層列進行重命名和排序

# 對第一層的列重命名
a.columns.set_leves(['Q1', 'Q2', 'Q3'], level=0, inplace=True)

# 對第一層的列重新排序
cats = ['Q2', 'Q3', 'Q1']    # 先定義一個新的順序
a = a.reindex(cats, axis=1, level=0)

這裏需要注意reindex函數沒有inplace的選項,所以要重新賦值回給a

自定義函數對指定列數據進行處理

現在有一個DataFrame df變量,其中有一列名爲’電話’,裏面的數據不太規矩,有的是空值,有的不是11位的手機號,現在需要將這些數據進行整理,通過自定義處理函數和apply(lambda)來實現:

import pandas as pd

df = pd.read_excel('1.xlsx')

# 自定義check函數,檢查傳入變量長度是否等於11位
def check(x):
    if len(str(x))!=11):
        return False
    else:
        return x


df['電話'].apply(lambda x: check(x))    # 這裏可以先查看一下返回處理後的'電話'列中的數據

df['電話'] = df['電話'].apply(lambda x: check(x))    # 直接修改原df中的數據,將不合格數據替換爲False

result = df[df['電話']!=False]    # 挑選出電話列合格的完整數據

# 附空值判斷:
df[df['鄉鎮'].isnull()]    # 挑選出鄉鎮列中是空值的完整行

df[df['鄉鎮'].notnull()]    # 挑選出鄉鎮列中不是空值的完整行

對數字類型列進行字符串slice分割處理

現在有一名爲"數據處理地"的列,內容類似410503100000,需要對其進行分割處理,只去開頭的6位數字

df['數據處理地'].astype(str).str.slice(0,6)

由於導入的xls文件默認會將數據處理地這一列識別爲int64數據類型,所以需要先使用.astype(str)將其轉換爲字符串類型,然後才能使用slice函數進行分割,slice()參數第一個是開始位置(首位爲0),第二個參數爲長度

對DataFrame的列重命名

# 直接重新賦值,注意需要將所有列名都寫到數組中
df.columns = ['列1', '列2', '列3']

# 使用rename,可以只對指定列重命名
df.rename(columns={'A':'列1', 'B':'列2', 'C':'列3'}, inplace = True)
對DataFrame單元值進行替換
df.replace({'A':1.2, 'B':3.2}, inplace=True)

# 使用字典映射方式進行替換,將所有值爲A的替換爲1.2,值爲B的替換爲3.2
# inplace參數=True將直接修改當前的df對象內容

創建相同結構的空DataFrame

根據df1創建一個新的DataFrame,擁有和df1相同的索引,列,但是數據都是nan

df2 = pd.DataFrame().reindex_like(df1)
# 將nan填充爲0,使用inplace參數就地處理(修改原df2對象),否則會返回一個新的df對象
df2.fillna(0, inplace=True)

兩個DataFrame進行相加(數據加法計算)

如果兩個要進行相加的df對象行和列完全相同,可以直接用df1 + df2這樣的表達式進行計算

import pandas as pd

df1 = pd.DataFrame([(1,2),(3,4),(5,6)], columns=['a','b'])
#    a  b
# 0  1  2
# 1  3  4
# 2  5  6
df2 = pd.DataFrame([(10,20),(30,40),(50,60)], columns=['a','b'])
#     a   b
# 0  10  20
# 1  30  40
# 2  50  60
result = df1 + df2
#    a   b
# 0  11  22
# 1  33  44
# 2  55  66

如果列相同,index索引不一樣

df1 = pd.DataFrame([(1,2),(3,4),(5,6)], columns=['a','b'], index=['d1', 'd2', 'd3'])
#     a  b
# d1  1  2
# d2  3  4
# d3  5  6
df2 = pd.DataFrame([(10,20),(30,40),(50,60),(70,80)], columns=['a','b'], index=['d1', 'd2', 'd3', 'd4'])
#      a   b
# d1  10  20
# d2  30  40
# d3  50  60
# d4  70  80
df1+df2
# 直接相加的話,d4行會變成NaN
#        a     b
# d1  11.0  22.0
# d2  33.0  44.0
# d3  55.0  66.0
# d4   NaN   NaN
df1.add(df2, fill_value=0)
# 使用.add並指定fill_value=0可以忽略df1中缺少的d4行(當做這行全是0繼續相加),結果如下:
#        a     b
# d1  11.0  22.0
# d2  33.0  44.0
# d3  55.0  66.0
# d4  70.0  80.0

# 繼續實驗,行相同,列不同
df3 = pd.DataFrame([(10,20,1),(30,40,2),(50,60,3),(70,80,4)], columns=['a','b','c'], index=['d1', 'd2', 'd3', 'd4'])
#      a   b  c
# d1  10  20  1
# d2  30  40  2
# d3  50  60  3
# d4  70  80  4
df2+df3
# 直接相加結果和上面類似,多出來的c列全是NaN
#       a    b   c
# d1   20   40 NaN
# d2   60   80 NaN
# d3  100  120 NaN
# d4  140  160 NaN
df2.add(df3, fill_value=0)
# 結果也和上面一樣
#       a    b    c
# d1   20   40  1.0
# d2   60   80  2.0
# d3  100  120  3.0
# d4  140  160  4.0
df1.add(df3, fill_value=0)
# 結果如預期一樣,多出來的行和列也都填充上了數據
#        a     b    c
# d1  11.0  22.0  1.0
# d2  33.0  44.0  2.0
# d3  55.0  66.0  3.0
# d4  70.0  80.0  4.0

使用where方法替換指定條件的數據

df3 = pd.DataFrame([(10,20,1),(30,0,2),(50,60,3),(70,80,4)], columns=['a','b','c'], index=['d1', 'd2', 'd3', 'd4'])

In [16]: df3
Out[16]:
     a   b  c
d1  10  20  1
d2  30   0  2
d3  50  60  3
d4  70  80  4

df3的數據如上,現在需要進行列計算a/b,但是b列中存在可能=0的情況,如果出現這樣的情況,需要使用c列中對應的值進行替換,具體實現:

df3['a']/df3['b'].where(df3['b']!=0,df3['c'])

這裏需要注意的是條件只有在=False的時候纔會返回後面的數據.where(條件, 條件=False時返回的數據)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章