大家好,小弟有兩個關於合併的問題想請教
1.資料合併一次只能兩個嗎,我目前用的方法是
(1)分別載入4筆資料
df1=pd.read_csv('202010_unc_bc05.csv')
df2=pd.read_csv('202010_unc_bc10.csv')
df3=pd.read_csv('202010_unc_bc15.csv')
df4=pd.read_csv('202010_unc_bc20.csv')
(2)篩選各資料出帳年月是202007的且重新給他一個新名稱
df11=df1.loc[df1['出帳年月']==202007]
df22=df2.loc[df2['出帳年月']==202007]
df33=df3.loc[df3['出帳年月']==202007]
df44=df4.loc[df4['出帳年月']==202007]
(3)分別合併並讀出
df5=df11.merge(df22,how='outer')
df6=df5.merge(df33,how='outer')
df7=df6.merge(df44,how='outer')
df7.to_csv('202007 D2.csv',index=False,encoding='utf_8_sig')
2.第二個問題是如果我有A、B兩個資料表,這兩筆資料分別有簽約日期
但A的簽約日期為空白B則是有資料,我用的方法如下
df3=df1.merge(df2,on='合約編號',how='left')
但會產出許多多餘的重複欄位,我想要的結果是B的簽約日期資料可以直接出現在A的簽約日期欄位裡,該怎麼做呢?謝謝~
Ans1:
import pandas as pd
import os
path = os.getcwd()
# List files:
files = os.listdir(path)
# 假設你的工作目錄下要找的是「202010_unc_bc*.csv」的檔案
files_csv = [f for f in files if f[:13] == '202010_unc_bc']
df = pd.DataFrame()
for f in files_csv:
# 假設你的csv檔欄位都是第1列,重複讀檔時,要把第1列去除
data = pd.read_csv(f, skiprows = 1)
df = df.append(data)
# 不確定你的出帳年月讀進df後是數字還是字串
df = df.loc[df['出帳年月'] == '202007']
df.to_csv('202007_D2.csv', index = False)
Ans2:
import numpy as np
df1 = pd.read_csv(file1)
df2 = pd.read_csv(file2)
# 只取df2的「合約編號」及「簽約日期」
df2 = df2[['合約編號', '簽約日期']]
# 先改一下欄位名稱
df2.rename(columns={'合約編號': '合約編號2', '簽約日期': '簽約日期2'})
# 將2個dataframe merge
df1 = pd.merge(df1, df2, left_on = '合約編號', right_on = '合約編號2', how = 'left')
# 新增一欄「新簽約日期」,當「合約編號」=「合約編號2」的時候,欄位值為「簽約日期2」,上述條件為非時,欄位值為「簽約日期」
df1['新簽約日期'] = np.where(df1['合約編號'] = df1['合約編號2'], df1['簽約日期2', df1['簽約日期'])
# 把不要的欄位名稱刪除
df1.drop(columns = ['合約編號2', '簽約日期2']
問題一在Google下對關鍵字就可找到範例這邊就不獻醜了,
關於問題二這邊提供一個土法鍊鋼的方法給樓主參考,會用到numpy作陣列比對,
這邊要訂好比對的規則,因為樓主關於txt內容及規則的部份沒講詳細,我就自己定義一下:
文件一 test1.txt(文件編碼:Big5)
主題 簽約日期 姓名 備註
測試1 2020/11/05 王小明 這是測試1
測試2 張學友 這是測試2
文件二 test2.txt(文件編碼:Big5)
主題 簽約日期 姓名 備註
測試2 2020/8/15 張學友 這是測試2
假設上列兩個文件都是在Excel編好匯出成tab分隔的文字檔(一般來說文件編碼可能會是Big5,如果內容有中文的話,直接讀入numpy會報錯,需先將Big5編碼轉成utf-8另存),然後將另存的test1_utf8.txt 及 test2_utf8.txt 讀入成numpy.array作合併,合併的判斷規則一是以test1為主,若test1的主題與test2的主題相同 且 test1的簽約日期為空白 且 test2的簽約日期不為空白的那一列,就把test2的簽約日期填進去。合併結果會用一個新的numpy.array回傳。
最後再把合併完成的numpy.array轉成pandas.dataframe(假如你有要用pandas作其它處理的話),
以下是範例程式:
import pandas as pd
import numpy as np
import codecs
def change_txt_encoding(src,dst,src_encoding,dst_encoding,BLOCKSIZE=1048576):
# or some other, desired size in bytes
with codecs.open(src, "r", src_encoding) as sourceFile:
with codecs.open(dst, "w", dst_encoding) as targetFile:
while True:
contents = sourceFile.read(BLOCKSIZE)
if not contents:
break
targetFile.write(contents)
def merge_by_sign_date(arr1, arr2):
out_arr = np.empty([len(arr1),4],dtype=object)
for i in range(len(arr1)):
out_arr[i]=arr1[i]
for j in arr2:
#假如該列test1.txt的簽約日期為空白且test2.txt的簽約日期不是空白
if j[0] == arr1[i][0] and arr1[i][1]=='' and j[1]!='':
#就把test2.txt的簽約日期代入同列C的簽約日期欄位
out_arr[i][1] = j[1]
return out_arr
#假如txt檔是用Excel編輯匯出的tab分隔之txt檔,它的文件編碼可能是Big5,若內含中文的話要用numpy讀取會有問題,需先轉成utf-8編碼
change_txt_encoding("test1.txt","test1_utf8.txt","Big5","utf-8")
change_txt_encoding("test2.txt","test2_utf8.txt","Big5","utf-8")
#舊文件是 test1.txt 與 test2.txt 文件編碼:Big5
#新文件是 test1_utf8.txt 與 test2_utf8.txt 文件編碼:Utf-8
test1_arr=np.loadtxt("test1_utf8.txt",dtype='str',delimiter='\t',encoding="utf-8")
test2_arr=np.loadtxt("test2_utf8.txt",dtype='str',delimiter='\t',encoding="utf-8")
print("test1.txt 轉 numpy.array:\n",test1_arr,'\n')
print("test2.txt 轉 numpy.array:\n",test2_arr,'\n')
test3_arr=merge_by_sign_date(test1_arr, test2_arr)
df = pd.DataFrame(data = test3_arr)
print('test2.txt 合併到 test1.txt 轉成 pandas.dataframe:\n',df)
註:
change_txt_encoding 函式作用: 將txt檔由編碼A轉編碼B再另存新txt檔
merge_by_sign_date 函式作用: 合併規則判斷,合併結果回傳為新的np.array
其實我的 numpy 跟 pandas 都不是很熟,只是之前工作上有用到類似的處理,這邊提供您一個學習參考,再複雜點的我就幫不上忙了。