Comparação entre Python e MySQL (4): Use Pandas para realizar o efeito de sintaxe de conversão de linha-coluna do MySQL

I. Introdução

Ambiente:
windows11 64-bit
Python3.9
MySQL8
pandas1.4.2

Este artigo apresenta principalmente a implementação e a comparação de sintaxe de vários problemas comuns de conversão de linha e coluna em Python e MySQL, incluindo: várias colunas são mescladas em uma coluna, várias linhas são mescladas em uma linha, uma coluna é dividida em várias colunas e uma linha é dividida em várias linhas, multi-linha para multi-coluna, multi-coluna para multi-linha.

Nota: Python é uma linguagem muito flexível. Pode haver várias maneiras de atingir o mesmo objetivo. O que forneço é apenas uma das soluções. Se você tiver outros métodos, deixe uma mensagem para discutirmos.

2. Comparação gramatical

Ficha de dados

Os dados usados ​​desta vez são os seguintes.
A sintaxe para construir este conjunto de dados usando Python é a seguinte:

import pandas as pd
import numpy as np

df1 = pd.DataFrame({
    
     'col1' : list(range(1,7))
                    ,'col2' : ['AA','AA','AA','BB','BB','BB']#list('AABCA')
                    ,'col3' : ['X',np.nan,'Da','Xi','Xa','xa']
                    ,'col4' : [10,5,3,5,2,None]
                    ,'col5' : [90,60,60,80,50,50]
                    ,'col6' : ['Abc','Abc','bbb','Cac','Abc','bbb']
                   })
df2 = pd.DataFrame({
    
    'col2':['AA','BB','CC'],'col7':[1,2,3],'col4':[5,6,7]})
df3 = pd.DataFrame({
    
    'col2':['AA','DD','CC'],'col8':[5,7,9],'col9':['abc,bcd,fgh','rst,xyy,ijk','nml,opq,wer']})

Obs: Basta colocar o código na célula do jupyter e executá-lo. A seguir, usamos diretamente df1, df2e df3chamamos os dados correspondentes. (Observe que o conjunto de dados df3 é diferente da seção anterior)

A sintaxe para construir este conjunto de dados usando o MySQL é a seguinte:

with t1 as(
  select  1 as col1, 'AA' as col2, 'X' as col3, 10.0 as col4, 90 as col5, 'Abc' as col6 union all
  select  2 as col1, 'AA' as col2, null as col3, 5.0 as col4, 60 as col5, 'Abc' as col6 union all
  select  3 as col1, 'AA' as col2, 'Da' as col3, 3.0 as col4, 60 as col5, 'bbb' as col6 union all
  select  4 as col1, 'BB' as col2, 'Xi' as col3, 5.0 as col4, 80 as col5, 'Cac' as col6 union all
  select  5 as col1, 'BB' as col2, 'Xa' as col3, 2.0 as col4, 50 as col5, 'Abc' as col6 union all
  select  6 as col1, 'BB' as col2, 'xa' as col3, null as col4, 50 as col5, 'bbb' as col6 
)
,t2 as(
  select  'AA' as col2, 1 as col7, 5 as col4 union all
  select  'BB' as col2, 2 as col7, 6 as col4 union all
  select  'CC' as col2, 3 as col7, 7 as col4 
)
,t3 as(
  select  'AA' as col2, 5 as col8, 'abc,bcd,fgh' as col9 union all
  select  'DD' as col2, 7 as col8, 'rst,xyy,ijk' as col9 union all
  select  'CC' as col2, 9 as col8, 'nml,opq,wer' as col9 
)
select * from t1;

Nota: Basta colocar o código na caixa de execução do código MySQL e executá-lo. Ao executar o código SQL posteriormente, o conjunto de dados (linhas 1 a 18 do código) é trazido por padrão e apenas a instrução de consulta é exibida, como a linha 19. (Observe que este conjunto de dados t3 é diferente da seção anterior e possui mais col9colunas)

A relação correspondente é a seguinte:

conjunto de dados Python conjunto de dados MySQL
df1 t1
df2 t2
df3 t3

concat (mesclar várias colunas em uma coluna)

O MySQL concat()pode concatenar várias colunas em uma coluna. Além dessa função, concat_ws()existem algumas diferenças no uso e nos resultados retornados das duas. concat()É para separar todos os campos ou caracteres que precisam ser unidos entre parênteses com vírgulas, e um concat_ws()delimitador precisa ser especificado, e o delimitador é usado uniformemente para dividir os dados. Veja o exemplo a seguir para obter detalhes.

Concatenação de dois campos não vazios -concat/concat_ws
Quando os campos MySQL são todos não vazios, o resultado é o mesmo concat()como concat_ws()se o mesmo delimitador fosse usado.
Em Python, o mesmo resultado pode ser obtido usando métodos como +, apply()+lambdaou . Deve-se observar que o MySQL converte implicitamente campos numéricos em strings e então os concatena, mas o Python não pode e precisa ser convertido manualmente.Você pode usar ou para converter.str.cat()
col5astype()map()

linguagem Pitão MySQL
o código 【Python1】
df1_1 = df1.copy()
df1_1['col5'] = df1_1.col5.astype('str')
df1_1.col2+'_'+df1_1.col5
【Python2】
df1_1 = df1.copy()
df1_1[' col5'] = df1_1.col5.astype('str')
df1_1.apply(lambda x:x.col2+'_'+x.col5,axis=1)
【Python3】
df1_1 = df1.copy()
df1_1['col5 '] = df1_1.col5.astype('str')
df1_1.col2.str.cat(df1_1.col5,sep='_')
【MySQL1】
selecione concat(col2,'_',col5) como col9 de t1;
【MySQL2】
selecione concat_ws('_',col2,col5)como col9 de t1;
resultado imagem.png imagem.png

Concatenação de vários campos (incluindo valores nulos) - concat/concat_ws retorna
quando um campo contém valores nulos e retorna a união de valores não nulos. Os resultados dos três métodos (conforme a seguir) usando dois campos de valor não nulo também são diferentes. Os resultados do uso de e são todos retornados (como mostrado em [Python1] e [Python2]), e usar o método tratará o valor nulo valor como , e todos os campos são emendados ​​​​( Como segue [Python3]). [Python1] e [Python2] alcançam o mesmo efeito, mas [Python3] não é exatamente o mesmo. Se você deseja obter o efeito desejado, pode adicionar uma etapa de processamento de valor de substituição com base em [Python3], como [Python4], além de ser substituído por uma string vazia.concat()nullconcat_ws()
+str.cat()nullapply()+lambdanan
concat()concat_ws()concat_ws().apply(lambda x:x.replace('_nan',''))_nan

linguagem Pitão MySQL
o código 【Python1】
df1_1 = df1.copy()
df1_1['col5'] = df1_1.col5.astype('str')
df1_1.col2+'_'+df1_1.col5+'_'+df1_1.col3
【Python2】
df1_1 = df1 .copy()
df1_1['col5'] = df1_1.col5.astype('str')
df1_1.col2.str.cat([df1_1.col5,df1_1.col3],sep='_')
【Python3】
df1_1 = df1.copy()
df1_1['col5'] = df1_1.col5.astype('str')
df1_1['col3'] = df1_1.col3.astype('str')
df1_1.apply(lambda x:x.col2+' _'+x.col5+'_'+x.col3,axis=1)
【Python4】
df1_1 = df1.copy()
df1_1['col5'] = df1_1.col5.astype('str')
df1_1['col3' ] = df1_1.col3.astype('str')
df1_1.apply(lambda x:x.col2+'_'+x.col5+'_'+x.col3,axis=1)\
.apply(lambda x:x. substituir('_nan',''))
selecione concat(col2,'_',col5,'_',col3) f_concat,concat_ws('_',col2,col5,col3) f_concat_ws de t1;
resultado [Resultados Python1 e Python2]
imagem.png
[Resultados Python3]
imagem.png
[Resultados Python4]
imagem.png
imagem.png

group_concat (várias linhas mescladas em uma linha)

As funções do MySQL group_concat()geralmente são usadas para agregar várias linhas de dados em uma linha de dados. No processo de agregação, várias situações diferentes estão envolvidas, vamos dar uma olhada em cada uma delas.

Agregação de campo único (string), sem classificação
Observe que há várias restrições aqui, deve ser um campo de string. Não há conversão implícita em Python. Se não for uma string, o tipo de dados precisa ser convertido. Consulte o método de conversão concat(), use astype()para converter.

linguagem Pitão MySQL
o código 【Python1】
df2 = df1.groupby('col2').apply(lambda x:','.join(x.col6)).reset_index().rename(columns={0:'col6'}) df2

Python2 】
df1.groupby(“col2”).agg({“col6”: lambda x: ','.join(x)}).reset_index()
selecione col2,group_concat(col6 separador ',') col6 do grupo t1 por col2;
resultado imagem.png imagem.png

聚合和排序为同一字段
当有排序时,不管聚合字段和排序字段是不是同个字段,在 MySQL 中加一个 order by 子句加上字段即可。
不过在 Python 的实现上二者有一些差异,同一字段时,可以在聚合的时候对列字段进行排序(如下 Python 代码)。

语言 Python MySQL
代码 df1.groupby(“col2”).agg({“col6”: lambda x: ‘,’.join(sorted(x, reverse=True))}).reset_index() select col2,group_concat(col6 order by col6 desc separator ‘,’) col6 from t1 group by col2;
结果 imagem.png imagem.png

聚合和排序为不同字段
当聚合字段和排序字段为不同字段时,就不可以使用上面的方法实现了,需要提前对数据排好序,再进行聚合(如下 Python 代码)。其实该语法通用性较好,同一字段也可以使用该语法,改一下排序的字段即可。

语言 Python MySQL
代码 df1.sort_values(by=[‘col5’],ascending=False).groupby(“col2”).agg({“col6”: lambda x: ‘,’.join(x)}).reset_index() # 先排序,再聚合。第二排序默认index select col2,group_concat(col6 order by col5 desc separator ‘,’) col6 from t1 group by col2;
结果 imagem.png imagem.png

去重聚合,聚合和排序必须为同一字段
去重聚合在 Python 中,可以看作是去重+同字段聚合排序的集合体,先去重,然后根据同一字段聚合排序的逻辑聚合起来。

语言 Python MySQL
代码 【Python1】
df1[[‘col2’,‘col6’]].drop_duplicates().sort_values(by=[‘col6’],ascending=False).groupby(“col2”).agg({“col6”: lambda x: ‘,’.join(x)}).reset_index()
【Python2】
df1.sort_values(by=[‘col6’],ascending=False).groupby(“col2”).agg({‘col6’:‘unique’}).agg({“col6”: lambda x: ‘,’.join(x)}).reset_index()
【Python3】
df1.sort_values(by=[‘col6’],ascending=False).groupby(“col2”).agg({‘col6’:‘unique’})[‘col6’].apply(lambda x:‘,’.join(x)).reset_index()
select col2,group_concat(distinct col6 order by col6 desc separator ‘,’) col6 from t1 group by col2;
结果 imagem.png imagem.png

多字段拼接并聚合
多字段拼接并聚合本质上就是使用concat()+group_concat() 进行实现。

语言 Python MySQL
代码 df1_1 = df1.copy()
df1_1[‘col5’] = df1_1.col5.astype(‘str’)
df1_1.groupby(‘col2’).apply(lambda x:‘,’.join(x.col6+‘_’+x.col5)).reset_index().rename(columns={0:‘col6’})
select col2,group_concat(concat(col6,‘_’,col5) order by col6 separator ‘,’) col6 from t1 group by col2;
结果 imagem.png imagem.png

一列拆分为多列

一列拆为多列,一般是在某一列有某些特征明显的数据规律,然后通过这些规律将数据拆开,变成多个列。在 MySQL 中,像t3.col9是有多个值通过逗号连在一起,这时候可以通过substring_index()识别逗号进行拆分(如下 MySQL 代码)。
在 Python 中,可以直接使用apply(pd.Series,index=['col_1','col_2','col_3'])实现对应的效果,然后再用pandas.concat()把需求字段拼接返回,如下【Python1】。当然,也可以使用类似 MySQL 的逻辑,分别处理每一个列,将df3.col9使用str.split()拆分开,然后通过索引分别取值,如下【Python2】

语言 Python MySQL
代码 【Python1】
df1_1 = df3.col9.apply(lambda x:x.split(‘,’)).apply(pd.Series,index=[‘col_1’,‘col_2’,‘col_3’])
pd.concat([df3.col2,df1_1],axis=1)
【Python2】
df3_1 = df3.copy()
df3_1[‘col_1’]=df3.col9.map(lambda x:x.split(‘,’)[0])
df3_1[‘col_2’]=df3.col9.map(lambda x:x.split(‘,’)[1])
df3_1[‘col_3’]=df3.col9.map(lambda x:x.split(‘,’)[2])
df3_1[[‘col2’,‘col_1’,‘col_2’,‘col_3’]]
select col2,substring_index(col9,‘,’,1)col_1,substring_index(substring_index(col9,‘,’,-1),‘,’,-1)col_2,substring_index(col9,‘,’,-1)col_3 from t3;
结果 imagem.png imagem.png

一行拆分为多行

一行拆分多行和一列拆分多列从字面上看都是一变多的逻辑,不过实现过程大不同。在 MySQL 中,需要借助一个连续增加的列来实现增加行的效果,然后针对每一行再对拆分后的字段进行取舍,如下 MySQL 代码。
在 Python 中,有一个专门将列表数据沿行向展开接口:pandas.explode()。只要将目标列的数据处理成列表的结构,便可直接使用它进行转化,如下 Python 代码。

语言 Python MySQL
代码 pd.concat([df3.col2,df3.col9.apply(lambda x:x.split(‘,’))],axis=1).explode(“col9”) select t3.col2,substring_index(substring_index(t3.col9,‘,’,t1.col1),‘,’,-1) col9
from t3
join t1 on t1.col1<=length(t3.col9)-length(replace(t3.col9,‘,’,‘’))+1
结果 imagem.png imagem.png

多行转为多列

多行转多列,在 MySQL 中,通常是通过max(case when)+group by实现,具体语法如下 MySQL 代码。
在 Python 中,则可以使用透视表方法pivot_table()实现。

语言 Python MySQL
代码 pd.pivot_table(df1, values=‘col5’, index=[‘col6’],columns=[‘col2’], aggfunc=np.max).reset_index() select col6,max(case when col2=‘AA’ then col5 end) “AA”,max(case when col2=‘BB’ then col5 end) “BB” from t1 group by col6;
结果 imagem.png imagem.png

多列转为多行

多列转多行,在 MySQL 中,其实就是将多列合并为一列,再通过一行转多行实现,即多列转为多行=多列转一列+一行拆分为多行(参考上文和以下 MySQL 代码)。
而 Python 中,有更多的实现方法,如下【Python1】,通过melt()方法便可直接将列值拍平,降维返回。如下【Python2】,通过stack()也可以实现相同的效果。二者不同点在于stack()是对所有的字段进行操作,所以需要把要保留的字段设置为索引,并只取需要拍平的列进行操作,而melt()更简便,直接指定对应的字段即可。
除了这两种方法,还可以使用和 MySQL 代码相同的逻辑,通过先拼接列再拆分行进行处理(如下【Python3】)

语言 Python MySQL
代码 【Python1】
df2.melt(id_vars=[‘col2’], value_vars=[‘col4’, ‘col7’],var_name=‘指标’, value_name=‘指标值’) # ignore_index=False不重置索引,默认重置
【Python2】
df2.set_index(‘col2’).stack().reset_index().rename(columns={‘level_1’:‘指标’,0:‘指标值’})
【Python3】
df2_1 = df2.copy()
df2_1[‘col4’] = df2_1.col4.astype(‘str’)
df2_1[‘col7’] = df2_1.col7.astype(‘str’)
df2_target = pd.concat([df2_1.col2,pd.Series([‘col4,col7’]*3).apply(lambda x:x.split(‘,’))],axis=1).explode(0).rename(columns={‘col2’:‘col’,0:‘指标’})
df2_value = pd.concat([df2_1.col2,df2_1.apply(lambda x:x.col4+‘,’+x.col7,axis=1).apply(lambda x:x.split(‘,’))],axis=1).explode(0).rename(columns={0:‘指标值’})
pd.concat([df2_target,df2_value],axis=1)[[‘col2’,‘指标’,‘指标值’]]
selecione t2.col2,if(t1.col1=1,'col4','col7') "index",substring_index(substring_index(concat(t2.col4,',',t2.col7),',',t1. col1),',',-1) "Valor do indicador"
de t2
junta t1 em t1.col1<=2
resultado imagem.png imagem.png

3. Resumo

Tanto o MySQL quanto o Python são muito flexíveis ao lidar com a conversão linha-coluna. Comparado com os dois, o Python será um pouco melhor, pois fornece mais interfaces, o que pode nos ajudar a processar os dados com mais flexibilidade e alcançar o efeito desejado. No entanto, o MySQL é relativamente mais conciso, com formato mais uniforme e sintaxe mais simples.

Acho que você gosta

Origin blog.csdn.net/qq_45476428/article/details/128681112
Recomendado
Clasificación