Ich habe einen 20 x 4000 Datenrahmen in Python mit Pandas. Zwei dieser Spalten heißen Year
und quarter
. Ich möchte eine Variable namens erstellenperiod
make Year = 2000
und quarter= q2
into2000q2
.
Kann mir jemand dabei helfen?
Ich habe einen 20 x 4000 Datenrahmen in Python mit Pandas. Zwei dieser Spalten heißen Year
und quarter
. Ich möchte eine Variable namens erstellenperiod
make Year = 2000
und quarter= q2
into2000q2
.
Kann mir jemand dabei helfen?
Antworten:
Wenn beide Spalten Zeichenfolgen sind, können Sie sie direkt verketten:
df["period"] = df["Year"] + df["quarter"]
Wenn eine (oder beide) der Spalten nicht vom Typ Zeichenfolge sind, sollten Sie sie zuerst konvertieren.
df["period"] = df["Year"].astype(str) + df["quarter"]
Wenn Sie mehrere Zeichenfolgenspalten verbinden müssen, können Sie Folgendes verwenden agg
:
df['period'] = df[['Year', 'quarter', ...]].agg('-'.join, axis=1)
Wobei "-" das Trennzeichen ist.
sum
.
dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"].map(str)
Zuordnung nur eine Zeichenfolgenkonvertierung auf alle Einträge anwenden.
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
df['period'] = df[['Year', 'quarter']].apply(lambda x: ''.join(x), axis=1)
Ergibt diesen Datenrahmen
Year quarter period
0 2014 q1 2014q1
1 2015 q2 2015q2
Diese Methode wird auf eine beliebige Anzahl von Zeichenfolgenspalten verallgemeinert, indem sie df[['Year', 'quarter']]
durch einen beliebigen Spaltenabschnitt Ihres Datenrahmens ersetzt wird, zdf.iloc[:,0:2].apply(lambda x: ''.join(x), axis=1)
.
Weitere Informationen zur Methode apply () finden Sie hier
lambda x: ''.join(x)
ist nur ''.join
nein?
lambda x: ''.join(x)
Konstruktion nichts tut; Es ist wie mit lambda x: sum(x)
statt nur zu verwenden sum
.
''.join
, dh : df['period'] = df[['Year', 'quarter']].apply(''.join, axis=1)
.
join
nur str
Instanzen in einer Iterable. Verwenden Sie a map
, um sie alle in zu konvertieren str
und dann zu verwenden join
.
[''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
oder etwas langsamer aber kompakter:
df.Year.str.cat(df.quarter)
df['Year'].astype(str) + df['quarter']
UPDATE: Zeitdiagramm Pandas 0.23.4
Testen wir es in 200K Zeilen 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: Neue Timings mit Pandas 0.19.0
Timing ohne CPU / GPU-Optimierung (sortiert vom schnellsten zum langsamsten):
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
Timing mit CPU / GPU-Optimierung:
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
Antwortbeitrag von @ anton-vbr
df.T.apply(lambda x: x.str.cat(sep=''))
Die Methode cat()
des .str
Accessors funktioniert hierfür sehr gut:
>>> 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()
Sie können sogar ein Trennzeichen hinzufügen, sodass Sie beispielsweise Folgendes annehmen können, wenn Sie beispielsweise nur Ganzzahlen für Jahr und Zeitraum haben:
>>> 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
Das Verbinden mehrerer Spalten besteht lediglich darin, entweder eine Liste von Serien oder einen Datenrahmen zu übergeben, der alle bis auf die erste Spalte als Parameter enthält, str.cat()
der in der ersten Spalte (Serie) aufgerufen werden soll:
>>> 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
Beachten Sie, dass Sie, wenn Ihr Pandas-Datenrahmen / Ihre Pandas-Serie Nullwerte enthält, den Parameter na_rep einschließen müssen, um die NaN-Werte durch eine Zeichenfolge zu ersetzen. Andernfalls wird in der kombinierten Spalte standardmäßig NaN verwendet.
lambda
oder map
; auch liest es nur am saubersten.
str.cat()
. Ich werde die Antwort ändern
sep
Schlüsselwort angeben ? in pandas-0.23.4. Vielen Dank!
sep
Parameter ist nur erforderlich, wenn Sie die Teile der verketteten Zeichenfolge trennen möchten. Wenn Sie eine Fehlermeldung erhalten, zeigen Sie uns bitte Ihr fehlerhaftes Beispiel.
Verwendung einer Lamba-Funktion dieses Mal mit 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
Auf diese Weise können Sie nach Bedarf mit Nicht-Zeichenfolgen arbeiten und Werte neu formatieren.
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
Einfache Antwort auf Ihre Frage.
year quarter
0 2000 q1
1 2000 q2
> df['year_quarter'] = df['year'] + '' + df['quarter']
> print(df['year_quarter'])
2000q1
2000q2
Year
es sich nicht um einen String handelt
df['Year'].astype(str) + '' + df['quarter'].astype(str)
Obwohl die @ silvado-Antwort gut ist, wenn Sie df.map(str)
zu ihr wechseln , df.astype(str)
wird sie schneller sein:
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
Nehmen wir an, Sie dataframe
sind df
mit Spalten Year
und Quarter
.
import pandas as pd
df = pd.DataFrame({'Quarter':'q1 q2 q3 q4'.split(), 'Year':'2000'})
Angenommen, wir möchten den Datenrahmen sehen.
df
>>> Quarter Year
0 q1 2000
1 q2 2000
2 q3 2000
3 q4 2000
Zum Schluss verketten Sie das Year
und das Quarter
wie folgt.
df['Period'] = df['Year'] + ' ' + df['Quarter']
Sie können jetzt print
df
den resultierenden Datenrahmen sehen.
df
>>> Quarter Year Period
0 q1 2000 2000 q1
1 q2 2000 2000 q2
2 q3 2000 2000 q3
3 q4 2000 2000 q4
Wenn Sie den Abstand zwischen Jahr und Quartal nicht möchten, entfernen Sie ihn einfach, indem Sie dies tun.
df['Period'] = df['Year'] + df['Quarter']
df['Period'] = df['Year'].map(str) + df['Quarter'].map(str)
TypeError: Series cannot perform the operation +
wenn ich entweder df2['filename'] = df2['job_number'] + '.' + df2['task_number']
oder renne df2['filename'] = df2['job_number'].map(str) + '.' + df2['task_number'].map(str)
.
df2['filename'] = df2['job_number'].astype(str) + '.' + df2['task_number'].astype(str)
aber funktioniert.
dataframe
, das ich oben erstellt habe, werden Sie sehen, dass alle Spalten string
s sind.
Hier ist eine Implementierung, die ich sehr vielseitig finde:
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
Wenn Ihre Daten in einen Datenrahmen eingefügt werden, sollte dieser Befehl Ihr Problem lösen:
df['period'] = df[['Year', 'quarter']].apply(lambda x: ' '.join(x.astype(str)), axis=1)
effizienter ist
def concat_df_str1(df):
""" run time: 1.3416s """
return pd.Series([''.join(row.astype(str)) for row in df.values], index=df.index)
und hier ist ein Zeittest:
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()
Wenn sum
(concat_df_str2) verwendet wird, ist das Ergebnis nicht einfach concat, sondern wird in eine Ganzzahl umgewandelt.
df.values[:, 0:3]
oder df.values[:, [0,2]]
.
Verallgemeinern auf mehrere Spalten, warum nicht:
columns = ['whatever', 'columns', 'you', 'choose']
df['period'] = df[columns].astype(str).sum(axis=1)
Die Verwendung zip
könnte noch schneller sein:
df["period"] = [''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
Graph:
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()
Einfachste Lösung:
Generische Lösung
df['combined_col'] = df[['col1', 'col2']].astype(str).apply('-'.join, axis=1)
Fragenspezifische Lösung
df['quarter_year'] = df[['quarter', 'year']].astype(str).apply(''.join, axis=1)
Geben Sie das bevorzugte Trennzeichen in den Anführungszeichen vor .join an
Diese Lösung verwendet einen Zwischenschritt, bei dem zwei Spalten des DataFrame zu einer einzelnen Spalte komprimiert werden, die eine Liste der Werte enthält. Dies funktioniert nicht nur für Zeichenfolgen, sondern für alle Arten von Spalten-d-Typen
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)
Ergebnis:
Year quarter list period
0 2014 q1 [2014, q1] 2014q1
1 2015 q2 [2015, q2] 2015q2
Wie bereits erwähnt, müssen Sie jede Spalte in eine Zeichenfolge konvertieren und dann mit dem Plus-Operator zwei Zeichenfolgenspalten kombinieren. Mit NumPy können Sie eine große Leistungsverbesserung erzielen.
%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)
-> Ausgabe : TypeError: ufunc 'add' did not contain a loop with signature matching types dtype('<U21') dtype('<U21') dtype('<U21')
. Sowohl job_number als auch task_number sind Ints.
df['Year'].values.astype(str) + df.quarter
Ich denke, der beste Weg, die Spalten in Pandas zu kombinieren, besteht darin, beide Spalten in Integer und dann in Str zu konvertieren.
df[['Year', 'quarter']] = df[['Year', 'quarter']].astype(int).astype(str)
df['Period']= df['Year'] + 'q' + df['quarter']
Hier ist meine Zusammenfassung der obigen Lösungen zum Verketten / Kombinieren von zwei Spalten mit dem Wert int und str zu einer neuen Spalte unter Verwendung eines Trennzeichens zwischen den Werten der Spalten. Zu diesem Zweck arbeiten drei Lösungen.
# 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)
Verwenden Sie .combine_first
.
df['Period'] = df['Year'].combine_first(df['Quarter'])
.combine_first
führt dazu, dass entweder der Wert 'Year'
in gespeichert 'Period'
wird oder, wenn er Null ist, der Wert aus 'Quarter'
. Die beiden Zeichenfolgen werden nicht verkettet und in gespeichert '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)
Zum Beispiel:
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"])
oder wenn Werte wie [2000] [4] sind und [2000q4] machen wollen
dataframe["period"] = dataframe["Year"].astype(str).add('q').add(dataframe["quarter"]).astype(str)
.astype(str)
durch .map(str)
Werke ersetzen .
add(dataframe.iloc[:, 0:10])
zum Beispiel?