Ho un dataframe 20 x 4000 in Python usando i panda. Due di queste colonne sono denominate Year
e quarter
. Mi piacerebbe creare una variabile chiamata period
che fa Year = 2000
e quarter= q2
in 2000q2
.
Qualcuno può aiutare con quello?
Ho un dataframe 20 x 4000 in Python usando i panda. Due di queste colonne sono denominate Year
e quarter
. Mi piacerebbe creare una variabile chiamata period
che fa Year = 2000
e quarter= q2
in 2000q2
.
Qualcuno può aiutare con quello?
Risposte:
se entrambe le colonne sono stringhe, puoi concatenarle direttamente:
df["period"] = df["Year"] + df["quarter"]
Se una (o entrambe) le colonne non sono tipizzate in stringa, dovresti prima convertirle (loro),
df["period"] = df["Year"].astype(str) + df["quarter"]
Se è necessario unire più colonne di stringa, è possibile utilizzare agg
:
df['period'] = df[['Year', 'quarter', ...]].agg('-'.join, axis=1)
Dove "-" è il separatore.
sum
.
dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"].map(str)
mappa sta semplicemente applicando la conversione di stringhe a tutte le voci.
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
df['period'] = df[['Year', 'quarter']].apply(lambda x: ''.join(x), axis=1)
Produce questo frame di dati
Year quarter period
0 2014 q1 2014q1
1 2015 q2 2015q2
Questo metodo si generalizza a un numero arbitrario di colonne stringa sostituendo df[['Year', 'quarter']]
con qualsiasi sezione di colonna del tuo frame di dati, ad es df.iloc[:,0:2].apply(lambda x: ''.join(x), axis=1)
.
Puoi controllare maggiori informazioni sul metodo apply () qui
lambda x: ''.join(x)
è solo ''.join
no?
lambda x: ''.join(x)
costruzione non fa nulla; è come usare lambda x: sum(x)
invece di solo sum
.
''.join
, cioè: df['period'] = df[['Year', 'quarter']].apply(''.join, axis=1)
.
join
accetta solo str
istanze in iterabile. Utilizzare a map
per convertirli tutti in, str
quindi utilizzare join
.
[''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
o leggermente più lento ma più compatto:
df.Year.str.cat(df.quarter)
df['Year'].astype(str) + df['quarter']
AGGIORNAMENTO: Grafico temporale Pandas 0.23.4
Proviamo su DF 200 righe:
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)
AGGIORNAMENTO: nuovi tempi usando Panda 0.19.0
Temporizzazione senza ottimizzazione CPU / GPU (ordinata dal più veloce al più 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
Temporizzazione mediante ottimizzazione 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
Risposta di contributo di @ anton-vbr
df.T.apply(lambda x: x.str.cat(sep=''))
Il metodo cat()
della .str
funzione di accesso funziona molto bene per questo:
>>> 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()
ti consente anche di aggiungere un separatore, quindi, ad esempio, supponi di avere solo numeri interi per anno e periodo, puoi farlo:
>>> 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
Unire più colonne è solo una questione di passare un elenco di serie o un frame di dati contenente tutte tranne la prima colonna come parametro da str.cat()
invocare sulla prima colonna (Serie):
>>> 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
Nota che se il tuo frame di dati panda / serie ha valori nulli, devi includere il parametro na_rep per sostituire i valori NaN con una stringa, altrimenti la colonna combinata verrà automaticamente impostata su NaN.
lambda
o map
; inoltre legge solo in modo più pulito.
str.cat()
.
sep
parola chiave? in panda-0.23.4. Grazie!
sep
parametro è necessario solo se si intende separare le parti della stringa concatenata. Se ricevi un errore, ti preghiamo di mostrarci il tuo esempio di errore.
L'uso di una funzione lamba questa volta con 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
Ciò consente di lavorare con non stringhe e riformattare i valori secondo necessità.
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
Risposta semplice per la tua domanda.
year quarter
0 2000 q1
1 2000 q2
> df['year_quarter'] = df['year'] + '' + df['quarter']
> print(df['year_quarter'])
2000q1
2000q2
Year
non è una stringa
df['Year'].astype(str) + '' + df['quarter'].astype(str)
Anche se la risposta @silvado è buona se si df.map(str)
passa ad df.astype(str)
essa sarà più veloce:
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
Supponiamo che il tuo dataframe
sia df
con colonne Year
e Quarter
.
import pandas as pd
df = pd.DataFrame({'Quarter':'q1 q2 q3 q4'.split(), 'Year':'2000'})
Supponiamo di voler vedere il frame di dati;
df
>>> Quarter Year
0 q1 2000
1 q2 2000
2 q3 2000
3 q4 2000
Infine, concatenare il Year
e il Quarter
seguente.
df['Period'] = df['Year'] + ' ' + df['Quarter']
Ora puoi print
df
vedere il frame di dati risultante.
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 non si desidera lo spazio tra l'anno e il trimestre, è sufficiente rimuoverlo facendo;
df['Period'] = df['Year'] + df['Quarter']
df['Period'] = df['Year'].map(str) + df['Quarter'].map(str)
TypeError: Series cannot perform the operation +
quando corro df2['filename'] = df2['job_number'] + '.' + df2['task_number']
o df2['filename'] = df2['job_number'].map(str) + '.' + df2['task_number'].map(str)
.
df2['filename'] = df2['job_number'].astype(str) + '.' + df2['task_number'].astype(str)
ha funzionato.
dataframe
che ho creato sopra, vedrai che tutte le colonne sono string
s.
Ecco un'implementazione che trovo molto versatile:
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
Man mano che i tuoi dati vengono inseriti in un dataframe, questo comando dovrebbe risolvere il tuo problema:
df['period'] = df[['Year', 'quarter']].apply(lambda x: ' '.join(x.astype(str)), axis=1)
è più efficiente
def concat_df_str1(df):
""" run time: 1.3416s """
return pd.Series([''.join(row.astype(str)) for row in df.values], index=df.index)
ed ecco un time test:
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
viene utilizzato (concat_df_str2), il risultato non è semplicemente concat, ma passerà all'intero.
df.values[:, 0:3]
o df.values[:, [0,2]]
.
generalizzando su più colonne, perché no:
columns = ['whatever', 'columns', 'you', 'choose']
df['period'] = df[columns].astype(str).sum(axis=1)
L'uso zip
potrebbe essere ancora più veloce:
df["period"] = [''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
Grafico:
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()
Soluzione più semplice:
Soluzione generica
df['combined_col'] = df[['col1', 'col2']].astype(str).apply('-'.join, axis=1)
Soluzione specifica per domande
df['quarter_year'] = df[['quarter', 'year']].astype(str).apply(''.join, axis=1)
Specificare il delimitatore preferito all'interno delle virgolette prima di .join
Questa soluzione utilizza un passaggio intermedio comprimendo due colonne di DataFrame in una singola colonna contenente un elenco di valori. Questo funziona non solo per le stringhe ma per tutti i tipi di tipi di colonna
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)
Risultato:
Year quarter list period
0 2014 q1 [2014, q1] 2014q1
1 2015 q2 [2015, q2] 2015q2
Come molti hanno già detto in precedenza, è necessario convertire ogni colonna in stringa e quindi utilizzare l'operatore più per combinare due colonne di stringa. È possibile ottenere un notevole miglioramento delle prestazioni utilizzando 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)
-> Output : TypeError: ufunc 'add' did not contain a loop with signature matching types dtype('<U21') dtype('<U21') dtype('<U21')
. Sia job_number che task_number sono ints.
df['Year'].values.astype(str) + df.quarter
Penso che il modo migliore per combinare le colonne in panda sia convertendo entrambe le colonne in numeri interi e poi in str.
df[['Year', 'quarter']] = df[['Year', 'quarter']].astype(int).astype(str)
df['Period']= df['Year'] + 'q' + df['quarter']
Ecco il mio riassunto delle soluzioni precedenti per concatenare / combinare due colonne con valore int e str in una nuova colonna, usando un separatore tra i valori delle colonne. Tre soluzioni funzionano a questo scopo.
# 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)
Usa .combine_first
.
df['Period'] = df['Year'].combine_first(df['Quarter'])
.combine_first
comporterà la 'Year'
memorizzazione del valore 'Period'
o, se è Null, il valore da 'Quarter'
. Non concatenerà le due stringhe e le memorizzerà '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)
Per esempio:
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"])
o se i valori sono come [2000] [4] e vogliono fare [2000q4]
dataframe["period"] = dataframe["Year"].astype(str).add('q').add(dataframe["quarter"]).astype(str)
sostituendo anche .astype(str)
con le .map(str)
opere.
add(dataframe.iloc[:, 0:10])
per esempio?