精华内容
下载资源
问答
  • 光年百度关键词分组工具,杭州光年(shop123)百度关键词分组工具主要是针对 “光年的百度关键词工具”推出的一款关键词切分,分组软件,将百度关键词工具导出的数据批量导入分
  • SEM关键词分组工具

    2014-08-18 22:36:35
    SEM分词工具,可将大量关键词细分至70分 关键词分组工具优选,您的关键词分组好帮手!
  • 快速实现关键词分组工具表,能够快速帮助你把大数量的词组进行快速分类,简单实用。 提醒:xls工具
  • 关键词快速分组工具

    2013-06-15 08:30:58
    关键词快速分组工具 关键词快速分组工具宏命令)改进版,百度竞价操作人员的效率提升工具
  • 快速实现关键词分组

    2018-06-05 15:17:32
    快速实现关键词分组工具表,能够快速帮助你把大数量的词组进行快速分类,简单实用。
  • 关键词分词工具

    2014-07-27 22:45:19
    录制宏 为关键词进行分组关键词分类 还可以筛选 够字数了吧
  • 需求很简单: 有一堆关键词(短句),需要给它们...例如这两个关键词都符合归类要求:日记软件,博客工具 又如:“社保&药店”,意思是把包含社保又包含药店的关键词归到一类。 例如:北京的社保药店就符合归...

    需求很简单:

    有一堆关键词(短句),需要给它们分组。分组逻辑很简单:给出一些归类词语,把包含这些归类词语的关键词归到一类。

    归类词语需要支持简单的与或算术逻辑,例如“日记|博客”,意思就是把包含日记或者博客关键词归到一类。

    例如这两个关键词都符合归类要求:日记软件,博客工具

    又如:“社保&药店”,意思是把包含社保又包含药店的关键词归到一类。

    例如:北京的社保药店就符合归类要求,但如果只是北京社保局就不符合归类要求

    再如:“(日记|博客)&(社保&药店)”,意思是把即符合“日记|博客”归类要求,又符合“社保&药店”归类要求的关键词归到一类。

     

    一个实际例子:

    现在有下面的关键词:

    附近专业保洁公司
    
    北京清洁公司
    
    家政公司
    
    北京好的家政公司
    
    保姆
    
    家教公司
    
    有名的家政
    
    口碑好的保姆


    归类词语如下:

    (专业|好的|有名)&(清洁|家政)&公司

    北京&家政

    附近

    保姆

    家政|清洁

    分类结果如下:

     

     这是另一个案例分词结果截图:

     

    其实这个需求在linux下直接用grep工具加上简单的shell还是很容易做的,但让我朋友为了这个从头学shell和linux不太现实,所以我帮他做了这个工具。如果有人有兴趣也可以去下载:

    下载地址:

    链接:https://pan.baidu.com/s/1r6YR8qJGOBxvA9GDPsevzw
    提取码:8dmn

    ===============================================

    下面是相关代码,里面用到了中序表达式转成后序表达式计算的技巧

    stdafx.h

     1 // stdafx.h : 标准系统包含文件的包含文件,
     2 // 或是经常使用但不常更改的
     3 // 特定于项目的包含文件
     4 //
     5 
     6 #pragma once
     7 
     8 #include "targetver.h"
     9 
    10 #include <stdio.h>
    11 #include <tchar.h>
    12 
    13 #define NUMOF(arr) (sizeof(arr)/sizeof(arr[0]))
    14 
    15 
    16 // TODO: 在此处引用程序需要的其他头文件
    17 #include <string>
    18 #include <vector>
    19 #include <iostream>
    20 #include <stack>
    21 using namespace std;

     

    GetWord.h

     1 #pragma once
     2 #include "stdafx.h"
     3 
     4 #define TYPE_WORD 0
     5 #define TYPE_AND 1
     6 #define TYPE_OR 2
     7 #define TYPE_BOOL 3
     8 #define TYPE_LEFT 4
     9 #define TYPE_RIGHT 5
    10 
    11 typedef struct 
    12 {
    13     int nWordType;
    14     string sValue;
    15 
    16     void output()
    17     {
    18         switch (nWordType)
    19         {
    20         case TYPE_WORD:
    21             cout << "TYPE_WORD " <<sValue << endl;
    22             break;
    23         case TYPE_AND:
    24             cout << "TYPE_AND" << endl;
    25             break;
    26         case TYPE_OR:
    27             cout << "TYPE_OR" << endl;
    28             break;
    29         case TYPE_BOOL:
    30             cout << "TYPE_BOOL" << endl;
    31             break;
    32         case TYPE_LEFT:
    33             cout << "TYPE_LEFT" << endl;
    34             break;
    35         case TYPE_RIGHT:
    36             cout << "TYPE_RIGHT" << endl;
    37             break;
    38         default:
    39             cout << "unknow" << endl;
    40             break;
    41         }
    42     }
    43 }ST_WORD;
    44 
    45 class CGetWord
    46 {
    47 public:
    48     CGetWord(const char *str);
    49     ~CGetWord(void);
    50     void rewrind(); //重置到开头
    51     bool getWord(ST_WORD &opr); //读取一个单词
    52 
    53 private:
    54     char *m_strInput;
    55     int m_nPos;
    56 };

    PostfixExpressions.h

     1 #pragma once
     2 #include "GetWord.h"
     3 
     4 class CPostfixExpressions
     5 {
     6 public:
     7     CPostfixExpressions(void);
     8     bool parse(const char *strIntermediateOrerExpressions); //输入中序 转换成后缀表达式 方便计算
     9     bool grep(const char *str); 
    10     ~CPostfixExpressions(void);
    11     void showExpr()
    12     {
    13         cout << "m_expr.size() = " << m_expr.size() << endl;
    14         for (size_t i = 0; i < m_expr.size(); ++i)
    15         {
    16             m_expr[i].output();
    17         }
    18     }
    19 private:
    20     vector<ST_WORD> m_expr;
    21 };

    targetver.h

    1 #pragma once
    2 
    3 // 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
    4 
    5 // 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
    6 // WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
    7 
    8 #include <SDKDDKVer.h>

    divide_group.cpp

      1 // divide_group.cpp : 定义控制台应用程序的入口点。
      2 //
      3 
      4 #include "stdafx.h"
      5 #include "GetWord.h"
      6 #include "PostfixExpressions.h"
      7 
      8 bool checkHaveNotGbk(const char *buf, const size_t nLen)
      9 {
     10     //检查是否有非GBK字符(不严谨)
     11     //碰到非英文字符
     12     bool bHaveNotGbk = false;
     13     for (size_t i = 0; i < nLen; ++i)
     14     {
     15         /*
     16         GBK 亦采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。
     17         总计 23940 个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。
     18         */
     19         unsigned char ch = buf[i];
     20         if ((ch & 0x80) != 0)
     21         {
     22             if (ch >= 0x81 && ch <= 0xfe)
     23             {
     24                 ch = buf[++i];
     25                 if (!(ch >= 0x40 && ch <= 0xFe && ch != 0x7F))
     26                 {
     27                     bHaveNotGbk = true;
     28                     break;
     29                 }
     30             }
     31             else
     32             {
     33                 bHaveNotGbk = true;
     34                 break;
     35             }
     36         }
     37     }
     38 
     39     return bHaveNotGbk;
     40 }
     41 
     42 char *getline(char *buf, size_t nBufSize, FILE *fp)
     43 {
     44     if ( fgets(buf, nBufSize, fp) == NULL)
     45     {
     46         return NULL;
     47     }
     48 
     49     size_t nLen = strlen(buf);
     50     if (nLen > 0 && buf[nLen - 1] == '\n')
     51     {
     52         buf[--nLen] = '\0';
     53     }
     54 
     55     if (checkHaveNotGbk(buf, nLen))
     56     {
     57         cerr << "疑似有非GBK编码字符[" << buf << "]" << endl;
     58         buf[0] = '\0';
     59     }
     60     return buf;
     61 }
     62 
     63 void outputResult(vector< vector<string> >& vecExprGrepSentence)
     64 {
     65     size_t nMaxJ = 0;
     66 
     67     for (size_t i = 0; i < vecExprGrepSentence.size(); ++i)
     68     {
     69         if (nMaxJ < vecExprGrepSentence[i].size())
     70         {
     71             nMaxJ = vecExprGrepSentence[i].size();
     72         }
     73     }
     74 
     75     for (size_t j = 0; j < nMaxJ; ++j)
     76     {
     77         for (size_t i = 0; i < vecExprGrepSentence.size(); ++i)
     78         {
     79             if (j < vecExprGrepSentence[i].size())
     80             {
     81                 cout << vecExprGrepSentence[i][j] << ",";
     82             }
     83             else
     84             {
     85                 cout << ",";
     86             }
     87         }
     88 
     89         cout << endl;
     90     }
     91 }
     92 
     93 int _tmain(int argc, _TCHAR* argv[])
     94 {
     95     if (argc < 3)
     96     {
     97         printf("usage:divide_group 词根文件 关键词文件\n");
     98         return 0;
     99     }
    100 
    101     bool bSplitMoreFlag = false; //标记一个关键词是否可以被多个词根匹配
    102     if (argc > 3 && argv[3][0] == '1')
    103     {
    104         bSplitMoreFlag = true;
    105     }
    106 
    107     vector<CPostfixExpressions> vecExprs;
    108     vector< vector<string> > vecExprGrepSentence;
    109 
    110     FILE *fpKey = fopen(argv[1], "r");
    111     if (fpKey == NULL)
    112     {
    113         cout << "词根文件打不开" << endl;
    114         return -1;
    115     }
    116 
    117 
    118     FILE *fpSentence = fopen(argv[2], "r");
    119     if (fpSentence == NULL)
    120     {
    121         cout << "关键词文件打不开" << endl;
    122         fclose(fpKey);
    123         return -10;
    124     }
    125 
    126     CPostfixExpressions expr;
    127     vector<string> vecGroup;
    128     char buf[1024];
    129     vecExprs.reserve(100);
    130     vecGroup.resize(1);
    131 
    132     while (getline(buf, sizeof(buf), fpKey))
    133     {
    134         if (buf[0] == '\0')
    135         {
    136             continue;
    137         }
    138 
    139         if (expr.parse(buf))
    140         {
    141             //暂时不处理
    142         }
    143         else
    144         {
    145             cerr << "词根[" << buf << "]异常 忽略" << endl;
    146         }
    147 
    148         vecExprs.push_back(expr);
    149         vecGroup[0] = buf;
    150         vecExprGrepSentence.push_back(vecGroup);
    151     }
    152 
    153     if (vecExprs.size() == 0)
    154     {
    155         cerr << "词根[" << buf << "]文件异常" << endl;
    156         return -20;
    157     }
    158 
    159     size_t nNoGrep = vecExprs.size();
    160     vecGroup[0] = "未分组";
    161     vecExprGrepSentence.push_back(vecGroup);
    162 
    163     while (getline(buf, sizeof(buf), fpSentence))
    164     {
    165         if (buf[0] == '\0')
    166         {
    167             continue;
    168         }
    169 
    170         bool bGrepFlag = false;
    171         for (size_t i = 0; i < vecExprs.size(); ++i)
    172         {
    173             if (vecExprs[i].grep(buf))
    174             {
    175                 vecExprGrepSentence[i].push_back(buf);
    176                 bGrepFlag = true;
    177 
    178                 if (!bSplitMoreFlag)
    179                 {
    180                     //关键字匹配到一个词根后就不再继续匹配
    181                     break;
    182                 }
    183             }
    184         }
    185 
    186         if (!bGrepFlag)
    187         {
    188             vecExprGrepSentence[nNoGrep].push_back(buf);
    189         }
    190     }
    191 
    192     outputResult(vecExprGrepSentence);
    193     fclose(fpKey);
    194     fclose(fpSentence);
    195     return 0;
    196 }

    GetWord.cpp

      1 #include "StdAfx.h"
      2 #include "GetWord.h"
      3 
      4 
      5 CGetWord::CGetWord(const char *str)
      6 {
      7     size_t nLen = strlen(str) + 1;
      8 
      9     m_strInput = new char[nLen];
     10     strcpy(m_strInput, str);
     11     m_nPos = 0;
     12 }
     13 
     14 
     15 CGetWord::~CGetWord(void)
     16 {
     17     delete []m_strInput;
     18     m_strInput = NULL;
     19     m_nPos = 0;
     20 }
     21 
     22 void CGetWord::rewrind()
     23 {
     24     m_nPos = 0;
     25 }
     26 
     27 //获取一个单词
     28 bool CGetWord::getWord(ST_WORD &opr)
     29 {
     30     char ch = m_strInput[m_nPos];
     31     if (ch == '\0')
     32     {
     33         return false;
     34     }
     35 
     36     opr.sValue = "";
     37     switch (ch)
     38     {
     39     case '&':
     40         opr.nWordType = TYPE_AND;
     41         ++m_nPos;
     42         break;
     43     case '|':
     44         opr.nWordType = TYPE_OR;
     45         ++m_nPos;
     46         break;
     47     case '(':
     48         opr.nWordType = TYPE_LEFT;
     49         ++m_nPos;
     50         break;
     51     case ')':
     52         opr.nWordType = TYPE_RIGHT;
     53         ++m_nPos;
     54         break;
     55     default:
     56         int i = 0;
     57         opr.nWordType = TYPE_WORD;
     58         for (i = m_nPos; m_strInput[i] != '\0'; ++i)
     59         {
     60             ch = m_strInput[i];
     61 
     62             //碰到操作符,说明关键字结束了
     63             if (ch == '&' || ch == '|' || ch == '(' || ch == ')')
     64             {
     65                 break;
     66             }
     67             else
     68             {
     69                 opr.sValue += ch;
     70 
     71                 if (ch & 0x80)
     72                 {
     73                     //中文 两个字符
     74                     ++i;
     75                     opr.sValue += m_strInput[i];
     76                     continue;
     77                 }
     78             }
     79         }
     80         m_nPos = i;
     81         break;
     82     }
     83 
     84     return true;
     85 }
     86 
     87 
     88 int testCGetWord()
     89 {
     90     char *strExpr[] = {"(计算机&专业)|广工",
     91         "计算机&广东",
     92         "计算机|好的|专业"};
     93 
     94     for (int i = 0; i < NUMOF(strExpr); ++i)
     95     {
     96         CGetWord expr(strExpr[i]);
     97         ST_WORD opr;
     98 
     99 
    100         cout << strExpr[i] << endl;
    101 
    102         while (expr.getWord(opr))
    103         {
    104             opr.output();
    105         }
    106 
    107         cout << "------------" << endl;
    108     }
    109     return 0;
    110 }

    PostfixExpressions.cpp

      1 #include "StdAfx.h"
      2 #include "PostfixExpressions.h"
      3 
      4 /*
      5 #define TYPE_WORD 0
      6 #define TYPE_AND 1
      7 #define TYPE_OR 2
      8 #define TYPE_BOOL 3
      9 #define TYPE_LEFT 4
     10 #define TYPE_RIGHT 5
     11 */
     12 
     13 const static int compare[6][6] =
     14 {
     15     0, 0, 0, 0, 0, 0,
     16     0, 1, -1, 0, -1, 0,
     17     0, 1, 1, 0, -1, 0, //TYPE_OR
     18     0, 0, 0, 0, 0, 0,
     19     0, -1, -1, 0, -1, 0, //TYPE_LEFT
     20     0, 1, 1, 0, 0, 0
     21 };
     22 
     23 CPostfixExpressions::CPostfixExpressions(void)
     24 {
     25 }
     26 
     27 
     28 CPostfixExpressions::~CPostfixExpressions(void)
     29 {
     30 }
     31 
     32 
     33 bool CPostfixExpressions::parse(const char *strIntermediateOrerExpressions)
     34 {
     35     /*
     36     InfixExp(中序表达式)转换PostfixExp(后序表达式)算法:
     37 
     38     1)当输入的是操作数时候,直接输出到后序表达式PostfixExp序列中
     39 
     40     2)当输入开括号时候,把它压栈
     41 
     42     3)当输入的是闭括号时候,先判断栈是否为空,若为空,则发生错误并进行相关处理。若非空,把栈中元素依次弹出并输出到Postfix中,知道遇到第一个开括号,若没有遇到开括号,也发生错误,进行相关处理
     43 
     44     4)当输入是运算符op(+、- 、×、/)时候
     45 
     46     a)循环,当(栈非空and栈顶不是开括号and栈顶运算符的优先级不低于输入的运算符的优先级)时,反复操作:将栈顶元素弹出并添加到Postfix中
     47 
     48     b)把输入的运算符op压栈
     49 
     50     5)当中序表达式InfixExp的符号序列全部读入后,若栈内扔有元素,把他们依次弹出并放到后序表达式PostfixExp序列尾部。若弹出的元素遇到空括号,则说明不匹配,发生错误,并进行相关处理
     51     */
     52     
     53     m_expr.clear();
     54     m_expr.reserve(100);
     55 
     56     CGetWord expr(strIntermediateOrerExpressions);
     57     ST_WORD opr;
     58     const ST_WORD *pOprTop;
     59 
     60     stack<ST_WORD> stackOperators;
     61     //vector<ST_WORD> vecSymbol;
     62 
     63     bool bExpectWord = true; //第一个元素必须是关键字
     64     while (expr.getWord(opr))
     65     {
     66         switch (opr.nWordType)
     67         {
     68         case TYPE_WORD:
     69             if (!bExpectWord)
     70             {
     71                 cerr << "语法错误1:不期望的关键字" << endl;
     72                 m_expr.clear();
     73                 return false;
     74             }
     75             m_expr.push_back(opr);
     76             bExpectWord = false; //不能出现连续关键字
     77             break;
     78         case TYPE_AND:
     79         case TYPE_OR:
     80             if (bExpectWord)
     81             {
     82                 cerr << "语法错误2:不期望的操作符" << endl;
     83                 m_expr.clear();
     84                 return false;
     85             }
     86             bExpectWord = true; //不能出现连续操作符
     87         case TYPE_LEFT:
     88             if (stackOperators.size() == 0)
     89             {
     90                 stackOperators.push(opr);
     91             }
     92             else
     93             {
     94                 pOprTop = &stackOperators.top();
     95 
     96                 while (compare[opr.nWordType][pOprTop->nWordType] > 0)
     97                 {
     98                     m_expr.push_back(*pOprTop);
     99                     stackOperators.pop();
    100 
    101                     if (stackOperators.size() == 0)
    102                     {
    103                         break;
    104                     }
    105 
    106                     pOprTop = &stackOperators.top();
    107                 }
    108 
    109                 stackOperators.push(opr);
    110             }
    111             break;
    112         case TYPE_RIGHT:
    113             if (stackOperators.size() == 0)
    114             {
    115                 cerr << "语法错误3:右括号不匹配左括号1" << endl;
    116                 m_expr.clear();
    117                 return false;
    118             }
    119             else
    120             {
    121                 const ST_WORD *pOprTop = &stackOperators.top();
    122 
    123                 while (compare[opr.nWordType][pOprTop->nWordType] > 0)
    124                 {
    125                     m_expr.push_back(*pOprTop);
    126                     stackOperators.pop();
    127 
    128                     if (stackOperators.size() == 0)
    129                     {
    130                         cerr << "语法错误4:右括号不匹配左括号2" << endl;
    131                         m_expr.clear();
    132                         break;
    133                     }
    134 
    135                     pOprTop = &stackOperators.top();
    136                 }
    137 
    138                 //把左括号出栈
    139                 stackOperators.pop();
    140             }
    141             break;
    142         default:
    143             cerr << "语法错误5:未知类型" << endl;
    144             m_expr.clear();
    145             return false;
    146         }
    147     }
    148 
    149     if (bExpectWord)
    150     {
    151         cerr << "语法错误6:缺少关键字" << endl;
    152         m_expr.clear();
    153         return false;
    154     }
    155 
    156     size_t nLeft = stackOperators.size();
    157 
    158     for (size_t i = 0; i < nLeft; ++i)
    159     {
    160         pOprTop = &stackOperators.top();
    161         if (pOprTop->nWordType == TYPE_LEFT)
    162         {
    163             cerr << "语法错误7:右括号不匹配左括号3" << endl;
    164             m_expr.clear();
    165             return false;
    166         }
    167         m_expr.push_back(*pOprTop);
    168         stackOperators.pop();
    169     }
    170 
    171     return true;
    172 }
    173 
    174 bool CPostfixExpressions::grep(const char *str)
    175 {
    176     if (m_expr.size() == 0)
    177     {
    178         cerr << "分组错误1,可能是表达式有问题" << endl;
    179         return false;
    180     }
    181 
    182 
    183     vector<ST_WORD> expr = m_expr;
    184 
    185     //先把关键字转换成布尔值
    186     for (size_t i = 0; i < expr.size(); ++i)
    187     {
    188         if (expr[i].nWordType == TYPE_WORD)
    189         {
    190             expr[i].nWordType = TYPE_BOOL;
    191             if (strstr(str, expr[i].sValue.c_str()) != NULL)
    192             {
    193                 expr[i].sValue = "1";
    194             }
    195             else
    196             {
    197                 expr[i].sValue = "0";
    198             }
    199         }
    200     }
    201 
    202     if (m_expr.size() == 1)
    203     {
    204         return expr[0].sValue[0] == '1';
    205     }
    206 
    207     stack<ST_WORD> stackOper;
    208     ST_WORD tmpResult;
    209     tmpResult.nWordType = TYPE_BOOL;
    210     tmpResult.sValue = "1";
    211 
    212     for (size_t i = 0; i < expr.size(); ++i)
    213     {
    214         if (expr[i].nWordType == TYPE_BOOL)
    215         {
    216             stackOper.push(expr[i]);
    217         }
    218         else
    219         {
    220             if (stackOper.size() < 2)
    221             {
    222                 cerr << "分组错误2,可能是表达式有问题" << endl;
    223                 return false;
    224             }
    225 
    226             const ST_WORD right = stackOper.top();
    227             stackOper.pop();
    228             const ST_WORD left = stackOper.top();
    229             stackOper.pop();
    230 
    231             int nResult;
    232 
    233             if (expr[i].nWordType == TYPE_AND)
    234             {
    235                 nResult = (left.sValue[0] - '0') && (right.sValue[0] - '0');
    236             }
    237             else
    238             {
    239                 nResult = (left.sValue[0] - '0') || (right.sValue[0] - '0');
    240             }
    241 
    242             tmpResult.sValue[0] = nResult + '0';
    243 
    244             //计算结果放回操作数堆栈
    245             stackOper.push(tmpResult);
    246         }
    247     }
    248 
    249     if (tmpResult.sValue[0] == '1')
    250     {
    251         return true;
    252     }
    253     else
    254     {
    255         return false;
    256     }
    257 }
    258 
    259 
    260 
    261 
    262 void testParse()
    263 {
    264     char *strExpr[] = {"单词",
    265         "双词&与",
    266         "双词&或",
    267         "三词&与|或",
    268         "三词|或&与",
    269         "三词&与&与",
    270         "三词|或|或",
    271         "(计算机&专业)|广工",
    272         "计算机&广东",
    273         "计算机|好的|专业",
    274         "(美丽|专业&低薪)|测试",
    275         "(计算机&帅哥)&广工",
    276         "(美丽&贤惠|计算机&专业)|广工&北大",
    277         "(计算机&帅哥)&广工(美丽&贤惠|计算机&专业)|广工&北大",
    278         "(计算机(帅哥&广工))",
    279         "((帅哥&广工)计算机)",
    280         "计算机(帅哥&广工))",
    281         "(计算机(帅哥&广工)",
    282         "计算机(帅哥&广工)",
    283         "&",
    284         "&&",
    285         "我&"};
    286 
    287     for (int i = 0; i < NUMOF(strExpr); ++i)
    288     {
    289         CPostfixExpressions expr;
    290 
    291 
    292         cerr << strExpr[i] << endl;
    293         if (expr.parse(strExpr[i]))
    294         {
    295             cerr << "语法正确" << endl;
    296             expr.showExpr();
    297         }
    298         else
    299         {
    300             cerr << "语法错误" << endl;
    301         }
    302         cerr << "------------" << endl;
    303     }
    304 }
    305 
    306 
    307 void testGrep(int argc, _TCHAR* argv[])
    308 {
    309     char *strExpr[] = {"(计算机&专业)|广工",
    310         "计算机&广东",
    311         "计算机|好的|专业",
    312         "(美丽|专业&低薪)|测试",
    313         "(计算机&帅哥)&广工",
    314         "计算机&(帅哥&广工)",
    315         "(美丽&贤惠|计算机&专业)|广工&北大",
    316         "(计算机|(帅哥&广工))",
    317         "广工",
    318         "我们"};
    319 
    320     char *strInput[] = {
    321         "计算机",
    322         "黄词辉",
    323         "广工",
    324         "专业",
    325         "黄词辉 计算机 广工毕业 帅哥",
    326         "美丽 计算机 广工毕业 贤惠",
    327         "专业 计算机 广工毕业 贤惠",
    328         "黄词辉 计算机 广工毕业 贤惠",
    329         "美丽 计算机 专业 帅哥",
    330         "低薪 计算机 专业 帅哥",
    331         "黄词辉 计算机 测试 帅哥",
    332         "我们曾经一起奋斗 广工"
    333     };
    334     //     testParse();
    335     //     return true;
    336     for (int i = 0; i < NUMOF(strExpr); ++i)
    337     {
    338         CPostfixExpressions expr;
    339 
    340 
    341         cerr << "词根:" << strExpr[i] << endl;
    342         if (expr.parse(strExpr[i]))
    343         {
    344             for (int j = 0; j < NUMOF(strInput); ++j)
    345             {
    346                 cerr << "匹配 " << strInput[j];
    347                 if (expr.grep(strInput[j]))
    348                 {
    349                     cerr << " 成功" << endl;
    350                 }
    351                 else
    352                 {
    353                     cerr << " 失败" << endl;
    354                 }
    355             }
    356         }
    357         else
    358         {
    359             cerr << "语法错误" << endl;
    360         }
    361         cerr << "------------" << endl;
    362     }
    363 }

    stdafx.cpp

    1 // stdafx.cpp : 只包括标准包含文件的源文件
    2 // divide_group.pch 将作为预编译头
    3 // stdafx.obj 将包含预编译类型信息
    4 
    5 #include "stdafx.h"
    6 
    7 // TODO: 在 STDAFX.H 中
    8 // 引用任何所需的附加头文件,而不是在此文件中引用

     

    转载于:https://www.cnblogs.com/kingstarer/p/10886607.html

    展开全文
  • 4、关键字分组管理,可实现复杂的关键监控条件。 5、十多种信息过滤方式,过滤无关信息骚扰。 6、详细记录监控历史,随时打开查阅。 7、支持多种报警方式,包括声音、弹窗、邮件、微信、手机QQ、短信提醒等。...
  • 大家好,今天给大家带来...来看一下今天的课程大纲:低价引流的关键词总计划建法我们一共是五个步骤:制作单品词表关键词分组分组词加入计划制作创意标题出价与推广01制作单品词表(通过卖点来找词)我们做低价引流计...
    e09c6cdd6675e28806c0e472b123649f.gif

    大家好,今天给大家带来的内容是车搜结合拉升流量的第14节课:直通车低价引流计划的关键词使用方法。我们之前讲过了搜索的关键词用法与直通车里面精准计划和广泛计划的关键词用法。今天我们来讲最后一种低价引流的关键词用法。

    来看一下今天的课程大纲:

    3023ad29636d1d50f22ed3c30a2488db.png

    低价引流的关键词总计划建法我们一共是五个步骤:

    制作单品词表

    关键词分组

    分组词加入计划

    制作创意标题

    出价与推广

    01制作单品词表(通过卖点来找词)

    我们做低价引流计划用的词可以非常多,也可以建很多的计划,一个产品,可以建好多好多计划,因为词是用不完的,非常多的,而且非常准。

    我们来看一下卖点在哪里?

    卖点还是你要看你自己这个宝贝本身的成交词的一些数据,比如说我们在流量纵横里面可以下载这个数据,流量纵横的单品数据。

    比方说我们看到流量纵横里面的女裤,我们可以看到很多的引流词以及它的访客数以及成交、转化率等等,看到这些数据,

    25e9a67bb35eda81ef9599a03448ea8b.png

    有了这些数据之后呢,我们可以下载下来去分析究竟在标题里面哪些词根是可以真正的带来成交和转化的。这个内容呢我们可以通过我们的软件标题词效率分析,把它自动算出来。(这个工具可以在公众号菜单里面直接下载。)

    1d4116b5eeae5fd914a52d06ea22ab23.png

    通过工具处理之后我们就有一个这样的数据,这是一个标题词效率分析的数据,这边是我们的标题拆分词,有很多的词根,每一个词根的数据怎么样的这里是能看出来的。

    8dadfbb425706de49fd2d4756280f620.png

    我们把优质词根找出来之后,再去我们的词表里面找搜索词,就这样一个流程。

    相当于是通过自己的宝贝数据过渡到市场数据上。

    那么我们是通过我们的工具箱去找,选择你的词表,然后把核心的词输进去,在词表里面就可以找到哪些市场词里面包含我们的优质词根。

    f497d05fde4cd527f6855da87e372b62.png

    最后我们可以把它搜出来,搜完之后这些搜索词就都包含了我们的优质词根,我们把它叫做核心相关词。

    18af3e9885e7ea6f5fa11a343fbfa3c7.png

    02关键词分组(根据不同指标维度进行分组)

    首先要算出来每一个关键词包含词根的数量是多少?究竟包含几个优质词根?算完之后,我们对它进行排序。

    f63a1bfa8d00ee49b48a298b5c296b01.png

    先把包含词根数量进行排序,把包含词根数量最多的而且搜索指数有一定指数的分成一组。

    e5d4c890cc0b7bf21c10006ea9e4676a.png

    剩下的词我们选择空白,因为还没有分过组,这些我们按照搜索人气单独来排序。

    33e02d7510c5643968ee833cf15e1ace.png

    比方说搜索指数在1万以上的,我们选200个词,搜索指数在5000到1万的我们再选200个搜索指数1000到5000的再选200个。

    把每一段都选出200个词做代表,这样的话我们就可以测试出来究竟什么样的人气的搜索词才是我们最好用的。

    0b119fb59f2d2921fef4b4548f2b5bec.png

    分组完了之后我们接下来就去投放。

    03分组词加入计划(广泛匹配加入到计划中)用广泛匹配的方式加入到计划当中。比方说我们一个案例:

    我们这是一个服装的案例,是做了五组词。分组一里面放的都是优质词根多的,分组二是1万以上的词,分组三是5000到1万的,分组四是1000到5000的,分组五就是1000以下的。用这样的一个方式把它们加到计划里面建好计划。然后自己设限额、出价,自己去评估就行。

    2b7156504d79ef791cb5407bf28e16b4.png

    在计划当中放进去之后,这些词就是这样子的,都是广泛匹配。

    2c6e615de2346f9f76d2a0f7c200176e.png

    这就是我们低价引流计划的建法。

    f32d58ed1c02522f3738d7473508c207.png最后希望大家有收获。想看更多精彩内容,请继续关注老梁电商哦!

    ·END·

    推荐阅读01b6bf1c0331f7fb60a1bda56e849ee9.png

    车搜结合拉升流量13丨直通车广泛匹配计划关键词用法

     ba6de40951c2295cdee1dce8d3bed3c3.png

    车搜结合拉升流量12丨直通车精准匹配计划关键词用法

     ec3bbdb7709cc889bd9a05dd27ae14d4.png

    车搜结合拉升流量11丨宝贝优化(三)优化规则

     bd5495e81f5307f8b05526c9abc1a84f.png

    车搜结合拉升流量10丨宝贝优化(二)补充词查找

     f6ac00154bc70bd6d80acdc132cb25af.png

    车搜结合拉升流量09丨宝贝优化(一)无效词查找

    643122f4632cff89927a9647a426c893.png

    车搜结合拉升流量08丨新品标题制作(二)

     bbed9a30c9e022e3531a2357ff844d30.png车搜结合拉升流量07 | 新品标题制作(一) 老梁电商

    更多精彩内容

    请关注公众号

    10a4328836aabef7e6f4ec9f9eb0b039.png

    添加大碗微信

    拉您进群开聊

    7e85b3003ceba402d24c4cf1e021b4ae.png

    53200b11a1fc0e0ee61b57ac2bb6da13.gif戳原文,查看更多《车搜结合拉升流量》信息!在看点一下,大家都知道
    展开全文
  • 关键词:pandas PyQt5数据透视文件合并前言 由于在工作中需要处理很多日志文件数据,这些数据并不存在于数据库,而是以每日1个单文件的形式存在,为了让我们在日常数据处理中更方便的进行一些基础的数据合并、清洗.....

    0f4e0f78a2259e6eecb6e0103f48a84b.png

    早起导读:pandas是Python数据处理的利器,如果每天都要使用pandas执行同样的操作,如何制作一个有界面的软件更高效的完成?本文提供了一种基于PyQt5的实现思路。

    关键词:pandas PyQt5 数据透视 文件合并

    前言

    由于在工作中需要处理很多日志文件数据,这些数据并不存在于数据库,而是以每日1个单文件的形式存在,为了让我们在日常数据处理中更方便的进行一些基础的数据合并、清洗筛选以及简单的分组或数据透视处理,结合PyQt5pandas库,制作了一个简单的数据处理可视化工具。

    e9ab9846f8a6daf46340c06514566435.png

    执行效果

    我们运行脚本打包后的 exe 可执行文件,设定相关参数后点击“数据处理并导出”即可等待处理~

    以下是29文件共1400余万行数据的处理结果,差不多用了10分钟合并并处理导出所需结果~

    4f551fa3a0497f83db8ac9b3ac8d8af2.png

    1.窗体可视化设计

    采用PyQt5进行可视化界面设计,具体设计过程可以直接在QT designer中进行操作,然后转化为可视化界面的py文件。

    界面效果如下图:

    e386233806eb9c82387dd52fdcd56e67.png

    对于我们的操作界面,支持以下功能:

    • 选择原始数据所在的文件夹
    • 选择需要vlookup的文件所在的文件夹
    • 选择处理后结果导出的文件夹
    • 输入结果导出的文件名
    • 在原始数据中用于过滤筛选的字段
    • 在原始数据中用于过滤筛选的条件
    • 如果做数据透视的行(index)
    • 数据透视的列(column)
    • 用于计算的字段
    • 用于计算的方法

    2.多文件合并(concat)

    由于我们拿到的原始数据是以日期为文件名的csv文件,如果需要处理多天的数据,需要进行简单的数据合并后再做相关数据处理操作。

    这一步其实有4个操作:①获取文件夹下的文件列表 ②根据文件类型进行文件读取 ③对读取的文件进行简单的数据清洗 ④合并清洗后的数据

    2.1.获取文件夹下的文件列表

    获取文件夹下文件列表可以使用os.walk方法,产生3-元组 (dirpath, dirnames, filenames)【文件夹路径, 文件夹名字, 文件名】。

    根据文件夹路径+文件名即可组成改文件的绝对路径,用于后续文件读取。

    In  [1]: import os
        ...: 
        ...: location = r'F:\数据处理工具\测试数据'
        ...: filenames = os.walk(location)
        ...: 
        ...: #获取文件夹下全部文件的绝对路径
        ...: for fileName in os.walk(location):
        ...:     for table in fileName[2]:
        ...:         path = fileName[0] + '\\' + table
        ...:         print(path)
    F:\数据处理工具\测试数据\1.csv
    F:\数据处理工具\测试数据\2.csv
    F:\数据处理工具\测试数据\3.csv
    F:\数据处理工具\测试数据\4.csv
    F:\数据处理工具\测试数据\5.csv
    F:\数据处理工具\测试数据\6.csv
    F:\数据处理工具\测试数据\7.csv
    F:\数据处理工具\测试数据\8.csv
    F:\数据处理工具\测试数据\9.csv
    f60cda8fbbd62228e6e835e011d4790c.png

    2.2.根据文件类型进行文件读取

    由于在实际操作过程中,可能存在原始文件是csv压缩包zip格式,或者xlsx格式。我们需要根据文件名后缀进行判断,然后选择对应的读取文件数据方法。

    采用os.path.splitext(“文件路径”) 分离文件名与扩展名,默认返回(fname,fextension)元组。

    这里我们只考虑两种情况:csv(含zip)以及xlsx(含xls):

    if filetype == '.csv'or filetype == '.zip':
        Li = pd.read_csv(path, header=0)                        
    elif filetype == '.xlsx' or filetype == '.xls':
        Li = pd.read_excel(path, header=0)
    else:
        log = ''
        print(log)

    2.3.对读取的文件夹下简单的数据清洗

    对于读取的文件数据,并不是所有的数据都是我们需要用到的,或者说我们需要用到的数据可能是需要满足指定条件的。

    比如对于下面这个情况,读取 9.csv 文件后,我们看到 usernum 每个值出现的次数,然后我希望取满足uesrnum为10的数据。

    In [2]: df = pd.read_csv(r'F:\数据处理工具\测试数据\9.csv')
    In [3]: df.groupby('usernum').count()
    Out[3]: 
             @timestamp   appid  ...  truedmgtohero  victory
    usernum                      ...                        
    1            516999  516999  ...         516999   516999
    2             33970   33970  ...          33970    33970
    3             36819   36819  ...          36819    36819
    4              6917    6917  ...           6917     6917
    5              7855    7855  ...           7855     7855
    6             15416   15416  ...          15416    15416
    8              1220    1220  ...           1220     1220
    10            75420   75420  ...          75420    75420

    [8 rows x 71 columns]

    我们用到布尔索引即可df[df['usernum']==10]

    In [4]: df_10 = df[df['usernum']==10]
    In [5]: df_10.groupby('usernum').count()
    Out[5]: 
             @timestamp  appid  ...  truedmgtohero  victory
    usernum                     ...                        
    10            75420  75420  ...          75420    75420

    [1 rows x 71 columns]

    但是,因为我们的筛选字段及条件都是通过可视化操作界面进行输入的,输入的数据类型在程序中是字符串,所以我们需要将其处理成为可以用于条件筛选的形式。而且,我们在进行清洗的时候字段及条件可能是多个的。

    比如我输入的字段为:usernum/victory;输入的条件为:>=6/==1

    那我们实际上需要进行的清洗过程是df = df[df['usernum']>=6]df = df[df['victory']==1],为实现这个效果,可以用最简单的字符拼接的形式 s = f"Li['{checkli[0]}']{conditionli[0]}",然后进行eval(s)转化。

    #获取输入的筛选字段(用‘/’分割),我们用'/'拆分为列表
    checkli = self.lineEditcheck.text().split('/')
    #获取输入的条件参数(用‘/’分割),我们用'/'拆分为列表
    conditionli = self.lineEditcondition.text().split('/')
    for inum in range(len(checkli)):
        s = f"Li['{checkli[0]}']{conditionli[0]}"
        Li = Li[eval(s)]

    关于数据清洗处理,我们会在pandas学习笔记中进行详细介绍~

    2.4.合并清洗后的数据

    这一步就比较简单了,直接将需要合并的数据添加的列表中,然后concat合并即可。不过,需要做个简单的判断,如果原始只有1个文件,直接就取改文件即可;超过1个文件情况下,才需要执行合并操作。

        #...读取并清洗数据...
        fileList.append(Li)

    if len(fileList)>1:
        data_result = pd.concat(fileList, ignore_index=True)
    else:
        data_result = fileList[0]

    3.多文件拼接(merge)

    这个其实也比较简单,我们事先把需要用于横向拼接的文件放到指定目录后,读取文件列表逐一和第2节中的处理过的原始数据进行merge处理。

    基于第2节中介绍过的文件夹下文件列表读取,这里只介绍merge处理。

    还是一样的逻辑,先判断是否有需要merge的文件,然后再执行后续操作,我们需要用到左连接方式处理。

        #...读取需要用于merge的文件组合成列表...
        fileList.append(Li)
    for i in range(0,len(fileList)):
        data = pd.merge(data,fileList[i],how = 'left')

    4.数据处理(pivot_table和groupby)

    数据处理中我们可以用到pivot_table方法或者数据透视分组统计groupby方法,具体根据自己的需求选择。

    这一部分我们在后续 pandas学习笔记中也会详细介绍~

    4.1.数据透视(pivot_table)

    pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False)

    以下举例,简单介绍下其使用方式

    In  [6]: df = pd.DataFrame({"A": ["foo""foo""foo""foo""foo",
        ...:                          "bar""bar""bar""bar"],
        ...:                    "B": ["one""one""one""two""two",
        ...:                          "one""one""two""two"],
        ...:                    "C": ["small""large""large""small",
        ...:                          "small""large""small""small","large"],
        ...:                    "D": [1, 2, 2, 3, 3, 4, 5, 6, 7],
        ...:                    "E": [2, 4, 5, 5, 6, 6, 8, 9, 9]})
    In [7]: df
    Out[7]: 
         A    B      C  D  E
    0  foo  one  small  1  2
    1  foo  one  large  2  4
    2  foo  one  large  2  5
    3  foo  two  small  3  5
    4  foo  two  small  3  6
    5  bar  one  large  4  6
    6  bar  one  small  5  8
    7  bar  two  small  6  9
    8  bar  two  large  7  9

    # values是需要用于计算的字段,index是索引,columns是列,aggfunc是统计方式
    In  [8]: table = pd.pivot_table(df, values='D', index=['A''B'],
        ...:                     columns=['C'], aggfunc='sum')
    In [9]: table
    Out[9]: 
    C        large  small
    A   B                
    bar one    4.0    5.0
        two    7.0    6.0
    foo one    4.0    1.0
        two    NaN    6.0

    #如果aggfunc指定了多个统计方式,其会对计算的字段values中每个字段进行多个统计计算
    In [10]: table = pd.pivot_table(df, values=['D''E'], index=['A''C'],
        ...:                     aggfunc={'mean','sum'})
    In [11]: table
    Out[11]: 
                      D               E      
                   mean   sum      mean   sum
    A   C                                    
    bar large  5.500000  11.0  7.500000  15.0
        small  5.500000  11.0  8.500000  17.0
    foo large  2.000000   4.0  4.500000   9.0
        small  2.333333   7.0  4.333333  13.0

    #我们可以通过给aggfunc传递字典的形式指定每个用于计算字段的统计方式,这也是我们本次需要用到的
    In [12]: table = pd.pivot_table(df, values=['D''E'], index=['A''C'],
        ...:                     aggfunc={'D''mean','E''sum'})
    In [12]: table
    Out[12]: 
                      D   E
    A   C                  
    bar large  5.500000  15
        small  5.500000  17
    foo large  2.000000   9
        small  2.333333  13

    4.2.分组统计(groupby)

    DataFrame.groupby([]).agg(dict)

    分组统计是pandas很大的模块,这里也不做过多的介绍,大家可以关注后续 pandas学习笔记系列。

    简单举个例子:

    In [13]: df
    Out[13]: 
         A    B      C  D  E
    0  foo  one  small  1  2
    1  foo  one  large  2  4
    2  foo  one  large  2  5
    3  foo  two  small  3  5
    4  foo  two  small  3  6
    5  bar  one  large  4  6
    6  bar  one  small  5  8
    7  bar  two  small  6  9
    8  bar  two  large  7  9

    In [14]: df.groupby('A')['D'].mean()
    Out[14]: 
    A
    bar    5.5
    foo    2.2
    Name: D, dtype: float64

    #agg传字段参数更合适,可以和pivot_table统一化
    In [15]: df.groupby(['A']).agg({'D':'mean','E':'sum'})
    Out[15]: 
           D   E
    A           
    bar  5.5  32
    foo  2.2  22

    4.3.数据处理函数

    由于行列以及计算字段和方法都是在可视化操作界面输入,我们需要对获取参数后进行字符串有关处理,从而组合成为最终的计算方式。

    #获取输入的行、列、计算字段和方法
    hang = self.lineEditHang.text().split(',')
    lie = self.lineEditLie.text().split(','if len(self.lineEditLie.text())!=0 else []
    ziduan = self.lineEditJisuan.text().split(',')
    fangfa = self.lineEditJisF.text().split(',')

    将计算字段和计算方法进行组合成为字典

    dic = {}
    for i in range(len(fangfa)):
        #需要注意,这里对于非重复计数,其组合形式有点特别,不能用引号
           if fangfa[i] == 'pd.Series.nunique':
            dic[ziduan[i]] = eval(fangfa[i])
           else:
               dic[ziduan[i]] = fangfa[i]  

    判断在可视化操作界面是否选中了数据透视操作,然后执行数据处理

    if self.radioButton_toushi.isChecked():
        result = pd.pivot_table(df, values=ziduan,
                      aggfunc=dic, 
                      columns=lie,
                      index=hang,
                      ).reset_index()
    else:
        result = df.groupby(hang).agg(dic).reset_index()  

    5.总结

    以上主要三部分:

    • 先创建好可视化操作界面,
    • 然后编写功能槽函数和可视化操作界面功能进行关联,
    • 最后就是打包源代码成可执行文件exe。

    在进行每一步的操作时,最好都能加上边界条件处理,避免出现异常报错导致程序崩溃的情况。

    每个槽函数其实都是利用到的python基础知识或者pandas基础数据处理知识,熟练掌握后便可很方便理解和实现。

    :后台回复「0906」获取本文涉及的完整源码!

    -END-

    d8571a149d03f0435ff8e16f292deeff.png

    8daf206b274583a05cc631c5bce358ab.png

    展开全文
  • 关键词:pandas PyQt5数据透视文件合并前言 由于在工作中需要处理很多日志文件数据,这些数据并不存在于数据库,而是以每日1个单文件的形式存在,为了让我们在日常数据处理中更方便的进行一些基础的数据合并、清洗.....

    a3b223f4843cdc7cad1c7d2feabbb9c9.gif

    早起导读:pandas是Python数据处理的利器,如果每天都要使用pandas执行同样的操作,如何制作一个有界面的软件更高效的完成?本文提供了一种基于PyQt5的实现思路。

    关键词:pandas PyQt5 数据透视 文件合并

    前言

    由于在工作中需要处理很多日志文件数据,这些数据并不存在于数据库,而是以每日1个单文件的形式存在,为了让我们在日常数据处理中更方便的进行一些基础的数据合并、清洗筛选以及简单的分组或数据透视处理,结合PyQt5pandas库,制作了一个简单的数据处理可视化工具。

    f2237853651588f073f86345b1b545be.png

    执行效果

    我们运行脚本打包后的 exe 可执行文件,设定相关参数后点击“数据处理并导出”即可等待处理~

    以下是29文件共1400余万行数据的处理结果,差不多用了10分钟合并并处理导出所需结果~

    f38a93de07f5c14766b2bb6bb1f0d7af.png

    1.窗体可视化设计

    采用PyQt5进行可视化界面设计,具体设计过程可以直接在QT designer中进行操作,然后转化为可视化界面的py文件。

    界面效果如下图:

    5aab2e47f7f2d5f6db6c5bece16fde21.png

    对于我们的操作界面,支持以下功能:

    • 选择原始数据所在的文件夹
    • 选择需要vlookup的文件所在的文件夹
    • 选择处理后结果导出的文件夹
    • 输入结果导出的文件名
    • 在原始数据中用于过滤筛选的字段
    • 在原始数据中用于过滤筛选的条件
    • 如果做数据透视的行(index)
    • 数据透视的列(column)
    • 用于计算的字段
    • 用于计算的方法

    2.多文件合并(concat)

    由于我们拿到的原始数据是以日期为文件名的csv文件,如果需要处理多天的数据,需要进行简单的数据合并后再做相关数据处理操作。

    这一步其实有4个操作:①获取文件夹下的文件列表 ②根据文件类型进行文件读取 ③对读取的文件进行简单的数据清洗 ④合并清洗后的数据

    2.1.获取文件夹下的文件列表

    获取文件夹下文件列表可以使用os.walk方法,产生3-元组 (dirpath, dirnames, filenames)【文件夹路径, 文件夹名字, 文件名】。

    根据文件夹路径+文件名即可组成改文件的绝对路径,用于后续文件读取。

    In  [1]: import os
        ...: 
        ...: location = r'F:\数据处理工具\测试数据'
        ...: filenames = os.walk(location)
        ...: 
        ...: #获取文件夹下全部文件的绝对路径
        ...: for fileName in os.walk(location):
        ...:     for table in fileName[2]:
        ...:         path = fileName[0] + '\\' + table
        ...:         print(path)
    F:\数据处理工具\测试数据\1.csv
    F:\数据处理工具\测试数据\2.csv
    F:\数据处理工具\测试数据\3.csv
    F:\数据处理工具\测试数据\4.csv
    F:\数据处理工具\测试数据\5.csv
    F:\数据处理工具\测试数据\6.csv
    F:\数据处理工具\测试数据\7.csv
    F:\数据处理工具\测试数据\8.csv
    F:\数据处理工具\测试数据\9.csv
    7fe1d03dee30b28563044e09416ef43e.png

    2.2.根据文件类型进行文件读取

    由于在实际操作过程中,可能存在原始文件是csv压缩包zip格式,或者xlsx格式。我们需要根据文件名后缀进行判断,然后选择对应的读取文件数据方法。

    采用os.path.splitext(“文件路径”) 分离文件名与扩展名,默认返回(fname,fextension)元组。

    这里我们只考虑两种情况:csv(含zip)以及xlsx(含xls):

    if filetype == '.csv'or filetype == '.zip':
        Li = pd.read_csv(path, header=0)                        
    elif filetype == '.xlsx' or filetype == '.xls':
        Li = pd.read_excel(path, header=0)
    else:
        log = ''
        print(log)

    2.3.对读取的文件夹下简单的数据清洗

    对于读取的文件数据,并不是所有的数据都是我们需要用到的,或者说我们需要用到的数据可能是需要满足指定条件的。

    比如对于下面这个情况,读取 9.csv 文件后,我们看到 usernum 每个值出现的次数,然后我希望取满足uesrnum为10的数据。

    In [2]: df = pd.read_csv(r'F:\数据处理工具\测试数据\9.csv')
    In [3]: df.groupby('usernum').count()
    Out[3]: 
             @timestamp   appid  ...  truedmgtohero  victory
    usernum                      ...                        
    1            516999  516999  ...         516999   516999
    2             33970   33970  ...          33970    33970
    3             36819   36819  ...          36819    36819
    4              6917    6917  ...           6917     6917
    5              7855    7855  ...           7855     7855
    6             15416   15416  ...          15416    15416
    8              1220    1220  ...           1220     1220
    10            75420   75420  ...          75420    75420

    [8 rows x 71 columns]

    我们用到布尔索引即可df[df['usernum']==10]

    In [4]: df_10 = df[df['usernum']==10]
    In [5]: df_10.groupby('usernum').count()
    Out[5]: 
             @timestamp  appid  ...  truedmgtohero  victory
    usernum                     ...                        
    10            75420  75420  ...          75420    75420

    [1 rows x 71 columns]

    但是,因为我们的筛选字段及条件都是通过可视化操作界面进行输入的,输入的数据类型在程序中是字符串,所以我们需要将其处理成为可以用于条件筛选的形式。而且,我们在进行清洗的时候字段及条件可能是多个的。

    比如我输入的字段为:usernum/victory;输入的条件为:>=6/==1

    那我们实际上需要进行的清洗过程是df = df[df['usernum']>=6]df = df[df['victory']==1],为实现这个效果,可以用最简单的字符拼接的形式 s = f"Li['{checkli[0]}']{conditionli[0]}",然后进行eval(s)转化。

    #获取输入的筛选字段(用‘/’分割),我们用'/'拆分为列表
    checkli = self.lineEditcheck.text().split('/')
    #获取输入的条件参数(用‘/’分割),我们用'/'拆分为列表
    conditionli = self.lineEditcondition.text().split('/')
    for inum in range(len(checkli)):
        s = f"Li['{checkli[0]}']{conditionli[0]}"
        Li = Li[eval(s)]

    关于数据清洗处理,我们会在pandas学习笔记中进行详细介绍~

    2.4.合并清洗后的数据

    这一步就比较简单了,直接将需要合并的数据添加的列表中,然后concat合并即可。不过,需要做个简单的判断,如果原始只有1个文件,直接就取改文件即可;超过1个文件情况下,才需要执行合并操作。

        #...读取并清洗数据...
        fileList.append(Li)

    if len(fileList)>1:
        data_result = pd.concat(fileList, ignore_index=True)
    else:
        data_result = fileList[0]

    3.多文件拼接(merge)

    这个其实也比较简单,我们事先把需要用于横向拼接的文件放到指定目录后,读取文件列表逐一和第2节中的处理过的原始数据进行merge处理。

    基于第2节中介绍过的文件夹下文件列表读取,这里只介绍merge处理。

    还是一样的逻辑,先判断是否有需要merge的文件,然后再执行后续操作,我们需要用到左连接方式处理。

        #...读取需要用于merge的文件组合成列表...
        fileList.append(Li)
    for i in range(0,len(fileList)):
        data = pd.merge(data,fileList[i],how = 'left')

    4.数据处理(pivot_table和groupby)

    数据处理中我们可以用到pivot_table方法或者数据透视分组统计groupby方法,具体根据自己的需求选择。

    这一部分我们在后续 pandas学习笔记中也会详细介绍~

    4.1.数据透视(pivot_table)

    pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False)

    以下举例,简单介绍下其使用方式

    In  [6]: df = pd.DataFrame({"A": ["foo""foo""foo""foo""foo",
        ...:                          "bar""bar""bar""bar"],
        ...:                    "B": ["one""one""one""two""two",
        ...:                          "one""one""two""two"],
        ...:                    "C": ["small""large""large""small",
        ...:                          "small""large""small""small","large"],
        ...:                    "D": [1, 2, 2, 3, 3, 4, 5, 6, 7],
        ...:                    "E": [2, 4, 5, 5, 6, 6, 8, 9, 9]})
    In [7]: df
    Out[7]: 
         A    B      C  D  E
    0  foo  one  small  1  2
    1  foo  one  large  2  4
    2  foo  one  large  2  5
    3  foo  two  small  3  5
    4  foo  two  small  3  6
    5  bar  one  large  4  6
    6  bar  one  small  5  8
    7  bar  two  small  6  9
    8  bar  two  large  7  9

    # values是需要用于计算的字段,index是索引,columns是列,aggfunc是统计方式
    In  [8]: table = pd.pivot_table(df, values='D', index=['A''B'],
        ...:                     columns=['C'], aggfunc='sum')
    In [9]: table
    Out[9]: 
    C        large  small
    A   B                
    bar one    4.0    5.0
        two    7.0    6.0
    foo one    4.0    1.0
        two    NaN    6.0

    #如果aggfunc指定了多个统计方式,其会对计算的字段values中每个字段进行多个统计计算
    In [10]: table = pd.pivot_table(df, values=['D''E'], index=['A''C'],
        ...:                     aggfunc={'mean','sum'})
    In [11]: table
    Out[11]: 
                      D               E      
                   mean   sum      mean   sum
    A   C                                    
    bar large  5.500000  11.0  7.500000  15.0
        small  5.500000  11.0  8.500000  17.0
    foo large  2.000000   4.0  4.500000   9.0
        small  2.333333   7.0  4.333333  13.0

    #我们可以通过给aggfunc传递字典的形式指定每个用于计算字段的统计方式,这也是我们本次需要用到的
    In [12]: table = pd.pivot_table(df, values=['D''E'], index=['A''C'],
        ...:                     aggfunc={'D''mean','E''sum'})
    In [12]: table
    Out[12]: 
                      D   E
    A   C                  
    bar large  5.500000  15
        small  5.500000  17
    foo large  2.000000   9
        small  2.333333  13

    4.2.分组统计(groupby)

    DataFrame.groupby([]).agg(dict)

    分组统计是pandas很大的模块,这里也不做过多的介绍,大家可以关注后续 pandas学习笔记系列。

    简单举个例子:

    In [13]: df
    Out[13]: 
         A    B      C  D  E
    0  foo  one  small  1  2
    1  foo  one  large  2  4
    2  foo  one  large  2  5
    3  foo  two  small  3  5
    4  foo  two  small  3  6
    5  bar  one  large  4  6
    6  bar  one  small  5  8
    7  bar  two  small  6  9
    8  bar  two  large  7  9

    In [14]: df.groupby('A')['D'].mean()
    Out[14]: 
    A
    bar    5.5
    foo    2.2
    Name: D, dtype: float64

    #agg传字段参数更合适,可以和pivot_table统一化
    In [15]: df.groupby(['A']).agg({'D':'mean','E':'sum'})
    Out[15]: 
           D   E
    A           
    bar  5.5  32
    foo  2.2  22

    4.3.数据处理函数

    由于行列以及计算字段和方法都是在可视化操作界面输入,我们需要对获取参数后进行字符串有关处理,从而组合成为最终的计算方式。

    #获取输入的行、列、计算字段和方法
    hang = self.lineEditHang.text().split(',')
    lie = self.lineEditLie.text().split(','if len(self.lineEditLie.text())!=0 else []
    ziduan = self.lineEditJisuan.text().split(',')
    fangfa = self.lineEditJisF.text().split(',')

    将计算字段和计算方法进行组合成为字典

    dic = {}
    for i in range(len(fangfa)):
        #需要注意,这里对于非重复计数,其组合形式有点特别,不能用引号
           if fangfa[i] == 'pd.Series.nunique':
            dic[ziduan[i]] = eval(fangfa[i])
           else:
               dic[ziduan[i]] = fangfa[i]  

    判断在可视化操作界面是否选中了数据透视操作,然后执行数据处理

    if self.radioButton_toushi.isChecked():
        result = pd.pivot_table(df, values=ziduan,
                      aggfunc=dic, 
                      columns=lie,
                      index=hang,
                      ).reset_index()
    else:
        result = df.groupby(hang).agg(dic).reset_index()  

    5.总结

    以上主要三部分:

    • 先创建好可视化操作界面,
    • 然后编写功能槽函数和可视化操作界面功能进行关联,
    • 最后就是打包源代码成可执行文件exe。

    在进行每一步的操作时,最好都能加上边界条件处理,避免出现异常报错导致程序崩溃的情况。

    每个槽函数其实都是利用到的python基础知识或者pandas基础数据处理知识,熟练掌握后便可很方便理解和实现。

    :后台回复「0906」获取本文涉及的完整源码!

    -END-

    b4f91b09e5451d4b0507b4ee5140eb0d.png

    314f233111b1e3c9ae2ff3f2c3374b8f.gif

    展开全文
  • 百度竞价分词工具

    2013-12-31 17:59:03
    关键词自动分组工具,SEM竞价人员使用,快速便捷
  • 百度SEM分词工具终极版,里面包含精确分组表、模糊筛选表、分组后数据、最终展现等词根分组组合功能,能处理上万条关键词,将最终关键词数据导入百度推广计划中。
  • 好多粉-微信号复制统计工具,来粉统计,微信号复制统计系统更新落地页微信号自动控制功能,免费使用好多粉加粉统计,微信号复制统计,关键词复制统计工具,微信号在线管理等工具。使用方法:1. 第一步,新建微信号...
  • 博客备份工具

    2013-04-24 14:20:21
    【3】电子书chm格式(含图片,按文章类别分组)【强烈推荐】(chm):文件中含图片,无需连网,保持博客样式,按照文章类别进行分类,更加清晰,方便浏览。 【4】分页电子书(chm):可以设置分页,更适合微博电子书,...
  • 作为一个VIM党,日常工作开发中,会经常利用grep进行关键词搜索,以快速定位到文件。如图: 利用grep进行文本搜索 但是,这一过程会有两个效率问题: 展示的结果无法进行直接交互,需要手动粘贴文件路径在...
  • ---------------------------------- 建立分析逻辑 由上至下的搭建顺序 ... 2、拓词 百度推广的关键词拓展或者金华或者战神关键词工具9.1免费版 添加...3、整理 excel表格关键词分组 4、导入 excel导入到竞价客户...
  • 私信回复关键词工具】,获取Excel高效小工具合集!让你的Excel效率开挂~今天来教大家分组去除重复值、创建下拉菜单!戳这里回顾上节内容:去除重复值,一个函数轻松搞定,这个方法太简单了吧!(二)01分组去除重复...
  • 私信回复关键词工具】,获取Excel高效小工具合集!让你的Excel效率开挂~今天来教大家分组去除重复值、创建下拉菜单!戳这里回顾上节内容:去除重复值,一个函数轻松搞定,这个方法太简单了吧!(二)01分组去除重复...
  • moodle中年级、班级、小组研讨

    千次阅读 2012-11-16 17:11:56
    Moodle平台支持年级、班级、小组功能,提供了方便易用的分组工具。小组支持公开和封闭属性,配合教学功能模块,教师可以组织小组为单位的教学活动。 在Moodle中,年级、班级、小组主要是通过群组(cohorts)、大组...
  • 博客营销BlogUp

    2011-10-01 22:29:39
    九丁博客群发工具BlogUp是一款强大的博客营销工具,具有博客全自动群发、博客帐号辅助群建、帐号分组管理、博客文章可视化管理、文章伪原创、超链接自动插入、文章自动采集、关键词设置、标签设置、自动更换IP等核心...
  • 关键词 视频会议 目录服务 分组交换网 1 引言 在目前已成为计算机领域热点的群组协作计算工具中,视频会议系统是其中的一个重要组成部分。电路交换网络中的视频 会议系统已有较成熟的模型,如ITU的H.320标准等...
  • 随机插入指定关键字,定时发布文章,自动内容伪原创,分组参数设置,分组链接库互链,全自动监控挂机采集发布,自动更新网站首页栏目内页静态化等等。 芭奇站群软件 v16.09.25更新日志 1、增加自定义接口工具延时...
  • 随机插入指定关键字,定时发布文章,自动内容伪原创,分组参数设置,分组链接库互链,全自动监控挂机采集发布,自动更新网站首页栏目内页静态化等等...... 芭奇软件功能特点 1、不限制建站个数 芭奇站群营销软件...
  • 1. 订单宝:桌面版的订单接收处理工具,相当于阿里旺旺。来订单第一时间通知并处理。不错过任何订单。 2. 企通宝:网站管理员安装手机APP,随时随地通过APP管理网站后台数据。 OURPHP都有哪些功能? 多语言建站 =...
  • 077《Sourcegraph》阮一峰大佬推荐的github仓库关键词搜索工具 076《Listen1》Chrome听付费歌曲工具!免费听周杰伦的歌,网易云音乐,QQ音乐,虾米音乐,酷狗,酷我,哔哩哔哩,咪咕,一个扩展全搞定 075《Link to Text...
  •  6.9.2 使用抓包工具分析文件上传请求 176  6.9.3 上传多媒体文件方法封装 179  6.9.4 下载多媒体文件 183  6.9.5 案例:上传及下载语音文件 184  6.10 小结 185 第7章 网络表情的使用 186  7.1 微信...

空空如也

空空如也

1 2
收藏数 39
精华内容 15
关键字:

关键词分组工具