天天看點

Python|字元串資料清洗+分組計算Table of Contents問題背景總結遇到的坑導入相應的庫+定義函數處理流程封裝成函數資料

Table of Contents

  • 1  問題背景
  • 2  總結遇到的坑
  • 3  導入相應的庫+定義函數
  • 4  處理流程
    • 4.1  讀入資料
    • 4.2  篩選資料
    • 4.3  字元串處理
    • 4.4  對興趣點變量進行拆分
    • 4.5  分組計算
  • 5  封裝成函數

問題背景

最近在某網際網路公司實習,leader提了需求要處理一個資料,原始資料長這個樣子(注:為了資料隐私,已進行加密處理)

Python|字元串資料清洗+分組計算Table of Contents問題背景總結遇到的坑導入相應的庫+定義函數處理流程封裝成函數資料

需求是這個樣子的:

  • 需求1:将interests_news進行切分開成一條一條的,先處理一種情況:如果反斜杠隻取反斜杠後面的标簽,也就是二級标簽。處理完成之後,如果是逗号連接配接,具體如下:每一個标簽形成一行,後面對應三個變量保持一緻。
  • 處理ok後的資料結構如下:
    Python|字元串資料清洗+分組計算Table of Contents問題背景總結遇到的坑導入相應的庫+定義函數處理流程封裝成函數資料
  • 需求2:根據上述結果進行分組計算,也即根據興趣點标簽進行groupby 算users、ret_users的總和 以及兩個變量的比值
  • 最終結果如下:
    Python|字元串資料清洗+分組計算Table of Contents問題背景總結遇到的坑導入相應的庫+定義函數處理流程封裝成函數資料

總結遇到的坑

  • 字元串處理 用replace的時候 單引号要用雙引号去引 不能單引号再引單引号
  • groupby的時候如果少了元素 如果方法沒問題 那就是資料的坑 比如字元串有的多了空格 有的沒有空格 那就不一樣了
  • 要考慮情況更加全面一點

導入相應的庫+定義函數

import pandas as pd
import copy
import time

# 函數作用:反斜杠連接配接的多個元素取斜杠後面的一個元素
# 增加一個判斷 如果有多個元素 且有多個反斜杠 均要去考慮
def f1(x):
    s = x.split(',')
#     print(s)
    n = len(s)
    for i in range(n):
        if '/' in s[i]:
            s[i] = s[i].split('/')[1]
    return s
           

處理流程

讀入資料

data = pd.read_excel('./興趣點.xlsx', sheet_name='Sheet2')
data = data.dropna()
print(data.shape)
data.head()
           
(42934, 5)
           
day interests_news users ret_users 次留
1 20190311 ["娛樂/明星八卦"] 363.829957 2087 0.521120
2 20190311 ["健康/養生"] 27.469583 602 0.398086
3 20190311 ["娛樂/明星八卦","娛樂"] 411.894976 475 0.025857
4 20190311 ["體育/NBA"] 47.831449 432 0.058352
5 20190311 ["社會"] 183.316248 401 0.103651

篩選資料

data_10 = data[data['users'] > 5]
# 重新設定索引
data_10 = data_10.reset_index(drop=True)
print(data_10.shape)
data_10.head()
           
(403, 5)
           
day interests_news users ret_users 次留
20190311 ["娛樂/明星八卦"] 363.829957 2087 0.521120
1 20190311 ["健康/養生"] 27.469583 602 0.398086
2 20190311 ["娛樂/明星八卦","娛樂"] 411.894976 475 0.025857
3 20190311 ["體育/NBA"] 47.831449 432 0.058352
4 20190311 ["社會"] 183.316248 401 0.103651

字元串處理

# 先拷貝下資料
df = copy.deepcopy(data_10)
df['interests_news'] = df['interests_news'].apply(lambda x: x.replace('[', '').replace(']', '').replace('"', ''))
df['interests_news'] = df['interests_news'].map(f1).map(str)
df['interests_news'] = df['interests_news'].apply(lambda x: x.replace('[', '').replace(']', '').replace("'", ''))
print(df.shape)
df.head()
           
(403, 5)
           
day interests_news users ret_users 次留
20190311 明星八卦 363.829957 2087 0.521120
1 20190311 養生 27.469583 602 0.398086
2 20190311 明星八卦, 娛樂 411.894976 475 0.025857
3 20190311 NBA 47.831449 432 0.058352
4 20190311 社會 183.316248 401 0.103651

對興趣點變量進行拆分

思路梳理:

  • 其實就是一個DataFrame的拼接,定義幾個空list 然後對應的内容放進去 每次都形成一個新的DataFrame 形成過程先把數值不同的放在一起
  • 把所有的DataFrame都放到一個list 最後進行concat
# 思路:其實就是一個資料框的拼接 分别每次形成一個資料框
# 先定一個空清單
data_need = []
for i in range(len(df)):
    # 每次循環都清空興趣點清單
    int_news = []
    # 根據逗号進行切分
    s = df['interests_news'][i].split(',')
#     print(s)
#     break
    # 計算興趣點詞條的個數
    n = len(s)
    for j in range(n):
        # 将所有興趣點内容放到一個list
        int_news.append(s[j])
    # 形成資料框
    y = pd.DataFrame({'interests_news': int_news})
    # 補充其餘三列相同的資訊
    y['users'] = df['users'][i]
    y['ret_users'] = df['ret_users'][i]
    y['次留'] = df['次留'][i]
    # 單個資料框ok之後放到list中 
    data_need.append(y)
# 一起concat
data_new = pd.concat(data_need, axis = 0)
print(data_new.shape)
data_new.head()
           
(934, 4)
           
interests_news users ret_users 次留
明星八卦 363.829957 2087 0.521120
養生 27.469583 602 0.398086
明星八卦 411.894976 475 0.025857
1 娛樂 411.894976 475 0.025857
NBA 47.831449 432 0.058352

分組計算

思路梳理:

  • 先進行groupby
  • 然後對分組後的結果進行循環 然後再對每個子塊進行求和等等 結果都放到一個list裡面去 然後建構字典 形成DataFrame
  • 最後進行一個合并
# 重新設定索引
data_new = data_new.reset_index(drop=True)
# 删空格 後面groupby發現的坑
data_new['interests_news'] = data_new['interests_news'].apply(lambda x: x.strip())
# 定義四個空清單 用來裝每次分組計算的變量
interests_news = []
users = []
ret_users = []
ratio = []
# 進行groupby
dg1 = data_new.groupby('interests_news')
# 循環進行計算
for i in dg1:
    interests_news.append(i[0])
    users.append(i[1]['users'].sum())
    ret_users.append(i[1]['ret_users'].sum())
    ratio.append(i[1]['ret_users'].sum() / i[1]['users'].sum())
# 建構資料框
y = pd.DataFrame({'interests_news': interests_news, 
                 'users': users,
                 'ret_users': ret_users,
                 'ratio': ratio})
# 輸出
y.to_csv('大于5的使用者數分組計算結果.csv', index = False, encoding='gbk')
print(y.shape)
y.head()
           
(102, 4)
           
interests_news users ret_users ratio
CBA 173.707081 256 1.473745
1 NBA 392.799830 884 2.250510
2 三農 87.064592 91 1.045201
3 世界史 67.310528 48 0.713113
4 兩性 421.034683 405 0.961916

封裝成函數

import pandas as pd
import copy
import time

# 函數作用:反斜杠連接配接的多個元素取斜杠後面的一個元素
# 增加一個判斷 如果有多個元素 且有多個反斜杠 均要去考慮
def f1(x):
    s = x.split(',')
#     print(s)
    n = len(s)
    for i in range(n):
        if '/' in s[i]:
            s[i] = s[i].split('/')[1]
    return s

def Cleandata():
    t0 = time.time()
    # 1 讀入資料
    data = pd.read_excel('./興趣點.xlsx', sheet_name='Sheet2')
    data = data.dropna()
    print(data.shape)
    data.head()
    # 2 篩選資料
    data_10 = data[data['users'] > 5]
    # 重新設定索引
    data_10 = data_10.reset_index(drop=True)
    print(data_10.shape)
    # 3 字元串處理
    # 先拷貝下資料
    df = copy.deepcopy(data_10)
    df.head()
    df['interests_news'] = df['interests_news'].apply(lambda x: x.replace('[', '').replace(']', '').replace('"', ''))
    df['interests_news'] = df['interests_news'].map(f1).map(str)
    df['interests_news'] = df['interests_news'].apply(lambda x: x.replace('[', '').replace(']', '').replace("'", ''))
    # 4 對興趣點變量進行拆分
    # 思路:其實就是一個資料框的拼接 分别每次形成一個資料框
    # 先定一個空清單
    data_need = []
    for i in range(len(df)):
        # 每次循環都清空興趣點清單
        int_news = []
        # 根據逗号進行切分
        s = df['interests_news'][i].split(',')
        # 計算興趣點詞條的個數
        n = len(s)
        for j in range(n):
            # 将所有興趣點内容放到一個list
            int_news.append(s[j])
        # 形成資料框
        y = pd.DataFrame({'interests_news': int_news})
        # 補充其餘三列相同的資訊
        y['users'] = df['users'][i]
        y['ret_users'] = df['ret_users'][i]
        y['次留'] = df['次留'][i]
        # 單個資料框ok之後放到list中 
        data_need.append(y)
    # 一起concat
    data_new = pd.concat(data_need, axis = 0)
    print(data_new.shape)
    data_new.head()
    # 5 分組計算
    # 重新設定索引
    data_new = data_new.reset_index(drop=True)
    # 删空格 後面groupby發現的坑
    data_new['interests_news'] = data_new['interests_news'].apply(lambda x: x.strip())
    # 定義四個空清單 用來裝每次分組計算的變量
    interests_news = []
    users = []
    ret_users = []
    ratio = []
    # 進行groupby
    dg1 = data_new.groupby('interests_news')
    # 循環進行計算
    for i in dg1:
        interests_news.append(i[0])
        users.append(i[1]['users'].sum())
        ret_users.append(i[1]['ret_users'].sum())
        ratio.append(i[1]['ret_users'].sum() / i[1]['users'].sum())
    # 建構資料框
    y = pd.DataFrame({'interests_news': interests_news, 
                     'users': users,
                     'ret_users': ret_users,
                     'ratio': ratio})
    # 輸出
    y.to_csv('大于5的使用者數分組計算結果.csv', index = False, encoding='gbk')
    t1 = time.time()
    print('資料清洗完畢,所需時間為 %.2f s' % (t1-t0))
    return y.head()    
           
(42934, 5)
(403, 5)
(934, 4)
資料清洗完畢,所需時間為 3.58 s
           
interests_news users ret_users ratio
CBA 173.707081 256 1.473745
1 NBA 392.799830 884 2.250510
2 三農 87.064592 91 1.045201
3 世界史 67.310528 48 0.713113
4 兩性 421.034683 405 0.961916

資料

上述代碼所用到的資料

有興趣的小夥伴可以自己嘗試一波哦~