Eu tenho um dataframe 20 x 4000 em Python usando pandas. Duas dessas colunas são nomeadas Year
e quarter
. Eu gostaria de criar uma variável chamada period
that makes Year = 2000
and quarter= q2
into 2000q2
.
Alguém pode ajudar com isso?
Eu tenho um dataframe 20 x 4000 em Python usando pandas. Duas dessas colunas são nomeadas Year
e quarter
. Eu gostaria de criar uma variável chamada period
that makes Year = 2000
and quarter= q2
into 2000q2
.
Alguém pode ajudar com isso?
Respostas:
se as duas colunas forem cadeias, concatená-las diretamente:
df["period"] = df["Year"] + df["quarter"]
Se uma (ou ambas) das colunas não tiverem um tipo de string, você deve convertê-las (elas) primeiro,
df["period"] = df["Year"].astype(str) + df["quarter"]
Se você precisar ingressar em várias colunas de sequência, poderá usar agg
:
df['period'] = df[['Year', 'quarter', ...]].agg('-'.join, axis=1)
Onde "-" é o separador.
sum
.
dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"].map(str)
mapeamento apenas aplicando a conversão de string a todas as entradas.
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
df['period'] = df[['Year', 'quarter']].apply(lambda x: ''.join(x), axis=1)
Rende esse quadro de dados
Year quarter period
0 2014 q1 2014q1
1 2015 q2 2015q2
Este método generaliza para um número arbitrário de colunas de sequência, substituindo df[['Year', 'quarter']]
por qualquer fatia da coluna do seu quadro de dados, por exemplo df.iloc[:,0:2].apply(lambda x: ''.join(x), axis=1)
.
Você pode verificar mais informações sobre o método apply () aqui
lambda x: ''.join(x)
é só ''.join
, não?
lambda x: ''.join(x)
construção não faz nada; é como usar em lambda x: sum(x)
vez de apenas sum
.
''.join
, isto é,: df['period'] = df[['Year', 'quarter']].apply(''.join, axis=1)
.
join
leva apenas str
instâncias em um iterável. Use a map
para convertê-los todos em str
e depois use join
.
[''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
ou um pouco mais lento, mas mais compacto:
df.Year.str.cat(df.quarter)
df['Year'].astype(str) + df['quarter']
ATUALIZAÇÃO: Gráfico de tempo Pandas 0.23.4
Vamos testá-lo em 200 mil linhas DF:
In [250]: df
Out[250]:
Year quarter
0 2014 q1
1 2015 q2
In [251]: df = pd.concat([df] * 10**5)
In [252]: df.shape
Out[252]: (200000, 2)
UPDATE: novos horários usando o Pandas 0.19.0
Tempo sem otimização da CPU / GPU (classificado do mais rápido para o mais lento):
In [107]: %timeit df['Year'].astype(str) + df['quarter']
10 loops, best of 3: 131 ms per loop
In [106]: %timeit df['Year'].map(str) + df['quarter']
10 loops, best of 3: 161 ms per loop
In [108]: %timeit df.Year.str.cat(df.quarter)
10 loops, best of 3: 189 ms per loop
In [109]: %timeit df.loc[:, ['Year','quarter']].astype(str).sum(axis=1)
1 loop, best of 3: 567 ms per loop
In [110]: %timeit df[['Year','quarter']].astype(str).sum(axis=1)
1 loop, best of 3: 584 ms per loop
In [111]: %timeit df[['Year','quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1)
1 loop, best of 3: 24.7 s per loop
Tempo usando otimização de CPU / GPU:
In [113]: %timeit df['Year'].astype(str) + df['quarter']
10 loops, best of 3: 53.3 ms per loop
In [114]: %timeit df['Year'].map(str) + df['quarter']
10 loops, best of 3: 65.5 ms per loop
In [115]: %timeit df.Year.str.cat(df.quarter)
10 loops, best of 3: 79.9 ms per loop
In [116]: %timeit df.loc[:, ['Year','quarter']].astype(str).sum(axis=1)
1 loop, best of 3: 230 ms per loop
In [117]: %timeit df[['Year','quarter']].astype(str).sum(axis=1)
1 loop, best of 3: 230 ms per loop
In [118]: %timeit df[['Year','quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1)
1 loop, best of 3: 9.38 s per loop
Responder contribuição de @ anton-vbr
df.T.apply(lambda x: x.str.cat(sep=''))
O método cat()
do .str
acessador funciona muito bem para isso:
>>> import pandas as pd
>>> df = pd.DataFrame([["2014", "q1"],
... ["2015", "q3"]],
... columns=('Year', 'Quarter'))
>>> print(df)
Year Quarter
0 2014 q1
1 2015 q3
>>> df['Period'] = df.Year.str.cat(df.Quarter)
>>> print(df)
Year Quarter Period
0 2014 q1 2014q1
1 2015 q3 2015q3
cat()
ainda permite adicionar um separador, por exemplo, suponha que você só tenha números inteiros por ano e período, faça o seguinte:
>>> import pandas as pd
>>> df = pd.DataFrame([[2014, 1],
... [2015, 3]],
... columns=('Year', 'Quarter'))
>>> print(df)
Year Quarter
0 2014 1
1 2015 3
>>> df['Period'] = df.Year.astype(str).str.cat(df.Quarter.astype(str), sep='q')
>>> print(df)
Year Quarter Period
0 2014 1 2014q1
1 2015 3 2015q3
A união de várias colunas é apenas uma questão de passar uma lista de séries ou um quadro de dados contendo todos, exceto a primeira coluna, como um parâmetro a ser str.cat()
invocado na primeira coluna (Série):
>>> df = pd.DataFrame(
... [['USA', 'Nevada', 'Las Vegas'],
... ['Brazil', 'Pernambuco', 'Recife']],
... columns=['Country', 'State', 'City'],
... )
>>> df['AllTogether'] = df['Country'].str.cat(df[['State', 'City']], sep=' - ')
>>> print(df)
Country State City AllTogether
0 USA Nevada Las Vegas USA - Nevada - Las Vegas
1 Brazil Pernambuco Recife Brazil - Pernambuco - Recife
Observe que, se o dataframe / series do pandas tiver valores nulos, você precisará incluir o parâmetro na_rep para substituir os valores de NaN por uma sequência, caso contrário, a coluna combinada será padronizada como NaN.
lambda
ou map
; também apenas lê de maneira mais limpa.
str.cat()
. Vou alterar a resposta
sep
palavra - chave? nos pandas-0.23.4. Obrigado!
sep
parâmetro é necessário apenas se você pretende separar as partes da sequência concatenada. Se você receber um erro, mostre-nos o seu exemplo com falha.
Agora, use uma função lamba com string.format ().
import pandas as pd
df = pd.DataFrame({'Year': ['2014', '2015'], 'Quarter': ['q1', 'q2']})
print df
df['YearQuarter'] = df[['Year','Quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1)
print df
Quarter Year
0 q1 2014
1 q2 2015
Quarter Year YearQuarter
0 q1 2014 2014q1
1 q2 2015 2015q2
Isso permite que você trabalhe com não-seqüências de caracteres e reformate valores, conforme necessário.
import pandas as pd
df = pd.DataFrame({'Year': ['2014', '2015'], 'Quarter': [1, 2]})
print df.dtypes
print df
df['YearQuarter'] = df[['Year','Quarter']].apply(lambda x : '{}q{}'.format(x[0],x[1]), axis=1)
print df
Quarter int64
Year object
dtype: object
Quarter Year
0 1 2014
1 2 2015
Quarter Year YearQuarter
0 1 2014 2014q1
1 2 2015 2015q2
Resposta simples para sua pergunta.
year quarter
0 2000 q1
1 2000 q2
> df['year_quarter'] = df['year'] + '' + df['quarter']
> print(df['year_quarter'])
2000q1
2000q2
Year
não for uma string
df['Year'].astype(str) + '' + df['quarter'].astype(str)
Embora a resposta @silvado é bom se você mudar df.map(str)
para df.astype(str)
ele vai ser mais rápido:
import pandas as pd
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
In [131]: %timeit df["Year"].map(str)
10000 loops, best of 3: 132 us per loop
In [132]: %timeit df["Year"].astype(str)
10000 loops, best of 3: 82.2 us per loop
Suponhamos que você dataframe
esteja df
com colunas Year
e Quarter
.
import pandas as pd
df = pd.DataFrame({'Quarter':'q1 q2 q3 q4'.split(), 'Year':'2000'})
Suponha que queremos ver o quadro de dados;
df
>>> Quarter Year
0 q1 2000
1 q2 2000
2 q3 2000
3 q4 2000
Finalmente, concatenar o Year
eo Quarter
da seguinte forma.
df['Period'] = df['Year'] + ' ' + df['Quarter']
Agora você pode print
df
ver o quadro de dados resultante.
df
>>> Quarter Year Period
0 q1 2000 2000 q1
1 q2 2000 2000 q2
2 q3 2000 2000 q3
3 q4 2000 2000 q4
Se você não deseja o espaço entre o ano e o trimestre, basta removê-lo fazendo;
df['Period'] = df['Year'] + df['Quarter']
df['Period'] = df['Year'].map(str) + df['Quarter'].map(str)
TypeError: Series cannot perform the operation +
quando corro um df2['filename'] = df2['job_number'] + '.' + df2['task_number']
ou outro df2['filename'] = df2['job_number'].map(str) + '.' + df2['task_number'].map(str)
.
df2['filename'] = df2['job_number'].astype(str) + '.' + df2['task_number'].astype(str)
funcionou.
dataframe
que criei acima, verá que todas as colunas são string
s.
Aqui está uma implementação que eu acho muito versátil:
In [1]: import pandas as pd
In [2]: df = pd.DataFrame([[0, 'the', 'quick', 'brown'],
...: [1, 'fox', 'jumps', 'over'],
...: [2, 'the', 'lazy', 'dog']],
...: columns=['c0', 'c1', 'c2', 'c3'])
In [3]: def str_join(df, sep, *cols):
...: from functools import reduce
...: return reduce(lambda x, y: x.astype(str).str.cat(y.astype(str), sep=sep),
...: [df[col] for col in cols])
...:
In [4]: df['cat'] = str_join(df, '-', 'c0', 'c1', 'c2', 'c3')
In [5]: df
Out[5]:
c0 c1 c2 c3 cat
0 0 the quick brown 0-the-quick-brown
1 1 fox jumps over 1-fox-jumps-over
2 2 the lazy dog 2-the-lazy-dog
Como seus dados são inseridos em um quadro de dados, este comando deve resolver seu problema:
df['period'] = df[['Year', 'quarter']].apply(lambda x: ' '.join(x.astype(str)), axis=1)
mais eficiente é
def concat_df_str1(df):
""" run time: 1.3416s """
return pd.Series([''.join(row.astype(str)) for row in df.values], index=df.index)
e aqui está um teste do tempo:
import numpy as np
import pandas as pd
from time import time
def concat_df_str1(df):
""" run time: 1.3416s """
return pd.Series([''.join(row.astype(str)) for row in df.values], index=df.index)
def concat_df_str2(df):
""" run time: 5.2758s """
return df.astype(str).sum(axis=1)
def concat_df_str3(df):
""" run time: 5.0076s """
df = df.astype(str)
return df[0] + df[1] + df[2] + df[3] + df[4] + \
df[5] + df[6] + df[7] + df[8] + df[9]
def concat_df_str4(df):
""" run time: 7.8624s """
return df.astype(str).apply(lambda x: ''.join(x), axis=1)
def main():
df = pd.DataFrame(np.zeros(1000000).reshape(100000, 10))
df = df.astype(int)
time1 = time()
df_en = concat_df_str4(df)
print('run time: %.4fs' % (time() - time1))
print(df_en.head(10))
if __name__ == '__main__':
main()
final, quando sum
(concat_df_str2) é usado, o resultado não é simplesmente concat, ele será transferido para inteiro.
df.values[:, 0:3]
ou df.values[:, [0,2]]
.
generalizando para várias colunas, por que não:
columns = ['whatever', 'columns', 'you', 'choose']
df['period'] = df[columns].astype(str).sum(axis=1)
O uso zip
pode ser ainda mais rápido:
df["period"] = [''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
Gráfico:
import pandas as pd
import numpy as np
import timeit
import matplotlib.pyplot as plt
from collections import defaultdict
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
myfuncs = {
"df['Year'].astype(str) + df['quarter']":
lambda: df['Year'].astype(str) + df['quarter'],
"df['Year'].map(str) + df['quarter']":
lambda: df['Year'].map(str) + df['quarter'],
"df.Year.str.cat(df.quarter)":
lambda: df.Year.str.cat(df.quarter),
"df.loc[:, ['Year','quarter']].astype(str).sum(axis=1)":
lambda: df.loc[:, ['Year','quarter']].astype(str).sum(axis=1),
"df[['Year','quarter']].astype(str).sum(axis=1)":
lambda: df[['Year','quarter']].astype(str).sum(axis=1),
"df[['Year','quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1)":
lambda: df[['Year','quarter']].apply(lambda x : '{}{}'.format(x[0],x[1]), axis=1),
"[''.join(i) for i in zip(dataframe['Year'].map(str),dataframe['quarter'])]":
lambda: [''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
}
d = defaultdict(dict)
step = 10
cont = True
while cont:
lendf = len(df); print(lendf)
for k,v in myfuncs.items():
iters = 1
t = 0
while t < 0.2:
ts = timeit.repeat(v, number=iters, repeat=3)
t = min(ts)
iters *= 10
d[k][lendf] = t/iters
if t > 2: cont = False
df = pd.concat([df]*step)
pd.DataFrame(d).plot().legend(loc='upper center', bbox_to_anchor=(0.5, -0.15))
plt.yscale('log'); plt.xscale('log'); plt.ylabel('seconds'); plt.xlabel('df rows')
plt.show()
Solução mais simples:
Solução genérica
df['combined_col'] = df[['col1', 'col2']].astype(str).apply('-'.join, axis=1)
Pergunta specific solution
df['quarter_year'] = df[['quarter', 'year']].astype(str).apply(''.join, axis=1)
Especifique o delimitador preferido dentro das aspas antes de .join
Esta solução usa uma etapa intermediária compactando duas colunas do DataFrame em uma única coluna contendo uma lista dos valores. Isso funciona não apenas para strings, mas para todos os tipos de tipos de coluna
import pandas as pd
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
df['list']=df[['Year','quarter']].values.tolist()
df['period']=df['list'].apply(''.join)
print(df)
Resultado:
Year quarter list period
0 2014 q1 [2014, q1] 2014q1
1 2015 q2 [2015, q2] 2015q2
Como muitos mencionaram anteriormente, você deve converter cada coluna em sequência e, em seguida, usar o operador mais para combinar duas colunas de sequência. Você pode obter uma grande melhoria de desempenho usando o NumPy.
%timeit df['Year'].values.astype(str) + df.quarter
71.1 ms ± 3.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit df['Year'].astype(str) + df['quarter']
565 ms ± 22.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
df2['filename'] = df2['job_number'].values.astype(str) + '.' + df2['task_number'].values.astype(str)
-> Saída : TypeError: ufunc 'add' did not contain a loop with signature matching types dtype('<U21') dtype('<U21') dtype('<U21')
. Job_number e task_number são ints.
df['Year'].values.astype(str) + df.quarter
Eu acho que a melhor maneira de combinar as colunas nos pandas é convertendo ambas as colunas em número inteiro e depois em str.
df[['Year', 'quarter']] = df[['Year', 'quarter']].astype(int).astype(str)
df['Period']= df['Year'] + 'q' + df['quarter']
Aqui está o meu resumo das soluções acima para concatenar / combinar duas colunas com o valor int e str em uma nova coluna, usando um separador entre os valores das colunas. Três soluções funcionam para esse fim.
# be cautious about the separator, some symbols may cause "SyntaxError: EOL while scanning string literal".
# e.g. ";;" as separator would raise the SyntaxError
separator = "&&"
# pd.Series.str.cat() method does not work to concatenate / combine two columns with int value and str value. This would raise "AttributeError: Can only use .cat accessor with a 'category' dtype"
df["period"] = df["Year"].map(str) + separator + df["quarter"]
df["period"] = df[['Year','quarter']].apply(lambda x : '{} && {}'.format(x[0],x[1]), axis=1)
df["period"] = df.apply(lambda x: f'{x["Year"]} && {x["quarter"]}', axis=1)
Use .combine_first
.
df['Period'] = df['Year'].combine_first(df['Quarter'])
.combine_first
resultará no 'Year'
armazenamento do valor 'Period'
ou, se for nulo, no valor de 'Quarter'
. Não concatenará as duas seqüências e as armazenará 'Period'
.
def madd(x):
"""Performs element-wise string concatenation with multiple input arrays.
Args:
x: iterable of np.array.
Returns: np.array.
"""
for i, arr in enumerate(x):
if type(arr.item(0)) is not str:
x[i] = x[i].astype(str)
return reduce(np.core.defchararray.add, x)
Por exemplo:
data = list(zip([2000]*4, ['q1', 'q2', 'q3', 'q4']))
df = pd.DataFrame(data=data, columns=['Year', 'quarter'])
df['period'] = madd([df[col].values for col in ['Year', 'quarter']])
df
Year quarter period
0 2000 q1 2000q1
1 2000 q2 2000q2
2 2000 q3 2000q3
3 2000 q4 2000q4
dataframe["period"] = dataframe["Year"].astype(str).add(dataframe["quarter"])
ou se os valores são como [2000] [4] e desejam criar [2000q4]
dataframe["period"] = dataframe["Year"].astype(str).add('q').add(dataframe["quarter"]).astype(str)
substituindo .astype(str)
por .map(str)
obras também.
add(dataframe.iloc[:, 0:10])
por exemplo?