应用场景
选择铝一段时间的出厂价来进行比较,由于同一天可能有多家厂家给出报价,所以需要找出同一天有多家报价的情况,并且合并为一条数据,价格取各家价格的平均值。
import pymongo,pandas as pd
from bson import ObjectId
conn=pymongo.MongoClient()
cursor=conn.bulk_commodities.prices.find(
{'commodity_id':ObjectId("59b8fbadf00ab111208624f9"),
'price_type':'出厂价'}).sort('price_at',pymongo.ASCENDING)
aluminum_list=list(cursor)
aluminum_df=pd.DataFrame(aluminum_list)
# 删除columns 的方法
aluminum_df.drop(['commodity_id',
'company_id','price_type',
'priced_by','created_at','_id','price_at'],
axis=1,inplace=True)
# 刻意添加一条重复数据方便测试复杂情况
# 在dataframe 中添加 row 的方法
aluminum_df=aluminum_df.append(
pd.DataFrame({'publish_time':['2017-08-21'],
'price':[16082]}))
print '初始数据,2017-08-18 和 2017-08-21 两天都有重复数据'
print aluminum_df.head(10)
print aluminum_df.tail(1)
print '\n-------------------------------------------------'
# 找出指定的 column 中重复的 rows
# 这个方法很实用
d_rows=aluminum_df[aluminum_df['publish_time'].duplicated(keep=False)]
print '用duplicated方法找出的重复数据'
print d_rows
print '\n-------------------------------------------------'
# 曾经在这里犯过错,不能用下面的方法来删除
# 因为一边删除 aluminum_df, aluminum_df 的 index 也在发生变化!
# d_count=d_rows['price'].size
# for i in range(d_count):
# 删掉重复的 rows
# 这里 row_id 是固定的
# 不用考虑删除后会变化的问题
# aluminum_df.drop([d_rows.index[i]],axis=0,inplace=True)
# 正确的方法应该还是用 drop :
aluminum_df.drop(d_rows.index,axis=0,inplace=True)
# 将重复的数据分组
# 分组后取均值,分别创建新的 row
g_items=d_rows.groupby('publish_time').mean()
g_items['publish_time']=g_items.index
# 将新的 row加入到原有数据并且重整
aluminum_df=aluminum_df.append(g_items)
aluminum_df.sort_values(by='publish_time',inplace=True,ascending=False)
aluminum_df.set_index(aluminum_df['publish_time'],inplace=True)
aluminum_df.drop(['publish_time'],axis=1,inplace=True)
print '重整后的数据'
print aluminum_df.tail(8)
初始数据,2017-09-18 和 2017-09-21 两天都有重复数据
price publish_time
0 15780.0 2017-08-10
1 15740.0 2017-08-11
2 15660.0 2017-08-14
3 15430.0 2017-08-15
4 15840.0 2017-08-16
5 16200.0 2017-08-17
6 16170.0 2017-08-18
7 15920.0 2017-08-18
8 16070.0 2017-08-21
9 16000.0 2017-08-22
price publish_time
0 16082.0 2017-08-21
-------------------------------------------------
用duplicated方法找出的重复数据
price publish_time
6 16170.0 2017-08-18
7 15920.0 2017-08-18
8 16070.0 2017-08-21
0 16082.0 2017-08-21
-------------------------------------------------
重整后的数据
price
publish_time
2017-08-22 16000.0
2017-08-21 16076.0
2017-08-18 16045.0
2017-08-17 16200.0
2017-08-16 15840.0
2017-08-15 15430.0
2017-08-14 15660.0
2017-08-11 15740.0
总结
以上使用场景中,用到比较重要的知识点包括:
- 使用 pandas.DataFrame[ col_name ].duplicated(keep=False) 可以返回一个 DateFrame,元素都是 True/False,False 表示col_name对应的值有重复值;
- 如果第一条中得到的结果是 df_bool,那么要得到这些有重复值的 DataFrame 的所有数据,则需要用 pandas.DataFrame[ df_bool ]
- 如果第二条中得到的结果是 df_duplc,那么要分组计算均值并且返回一个 DataFrame,并且这个 DataFrame的index是第一条中的 DataFrame[col_name] 对应的值,需要用到 DataFrame.groupby('col_name').mean()
- 从 DataFrame 中删除整行或者整列,使用 DataFrame.drop( [name1,name2,...],axis=0/1, inplace=True/False),axis=0 表示删除整行,axis=1 表示删除整列
后记
事实上上面处理重复数据的思路还显得复杂了。原有的思路是先找出重复的行保存为一个 dataFrame01,然后在原有 dataFrame00 中删除所有重复的行;将 dataFrame01 做 groupby(...).mean() 运算得出 dataFrame02,dataFrame02 的index 是publish_time,且只有一列 price,price 的值是所有 publish_time 相同的行的均值;最后将 dataFrame02合并到 dataFrame00 中,按 publish_time 重新做排序。
去重更合理的思路应该是直接对 dataFrame00 做 groupby(by='publish_time).mean() 运算,然后对结果按 publish_time ( 这时 index 的值就是 publish_time ) 重新做排序就够了:
raw_df=raw_df.groupby(by='publish_time').mean()
raw_df.sort_index(ascending=False,inplace=True)
return raw_df