it-swarm.com.de

Kombinieren Sie zwei Textspalten im Datenrahmen in pandas / python

Ich habe einen 20 x 4000 Datenrahmen in python mit Pandas. Zwei dieser Spalten haben die Bezeichnung Jahr und Viertel. Ich möchte eine Variable namens period erstellen, die Year = 2000 und quarter = q2 zu 2000q2 macht

Kann mir jemand dabei helfen?

366
user2866103
dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"]
351
silvado
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 verallgemeinert auf eine beliebige Anzahl von Zeichenfolgenspalten, indem df[['Year', 'quarter']] durch einen beliebigen Spaltenabschnitt Ihres Datenrahmens ersetzt wird, z. df.iloc[:,0:2].apply(lambda x: ''.join(x), axis=1).

Sie können weitere Informationen zur Methode apply () hier überprüfen

227
Russ

Kleine Datenmengen (<150 Zeilen)

[''.join(i) for i in Zip(df["Year"].map(str),df["quarter"])]

oder etwas langsamer, aber kompakter:

df.Year.str.cat(df.quarter)

Größere Datensätze (> 150 Zeilen)

df['Year'].astype(str) + df['quarter']

UPDATE: Zeitdiagramm Pandas 0.23.4

enter image description here

Testen wir es mit 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 von schnellstem nach langsamstem):

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

Antwort Beitrag von @ anton-vbr

214
MaxU

Die Methode cat() des .str Accessors funktioniert 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

Mit cat() können Sie sogar ein Trennzeichen hinzufügen. Angenommen, Sie haben nur Ganzzahlen für Jahr und Periode.

>>> 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

Beim Verbinden mehrerer Spalten müssen Sie lediglich entweder eine Liste mit Reihen oder einen Datenrahmen mit allen Spalten außer der ersten als Parameter an str.cat() übergeben, der in der ersten Spalte (Reihe) aufgerufen wird:

>>> 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 den Parameter na_rep einfügen müssen, wenn Ihr pandas Datenrahmen/Ihre _ Datenreihe Nullwerte enthält, um die NaN-Werte durch eine Zeichenfolge zu ersetzen. Andernfalls wird in der kombinierten Spalte standardmäßig NaN verwendet.

140
LeoRochael

Verwendung einer Lamba-Funktion diesmal 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 mit Nicht-Zeichenfolgen arbeiten und Werte nach Bedarf 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
27
Bill Gale

Obwohl die @ silvado-Antwort gut ist, wenn Sie df.map(str) in df.astype(str) ändern, ist sie schneller:

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
12

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)
11
VickyK

Nehmen wir an, Ihr dataframe ist df mit den 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

Verketten Sie abschließend die Zeichen Year und Quarter wie folgt.

df['Period'] = df['Year'] + ' ' + df['Quarter']

Sie können jetzt printdf, um den resultierenden Datenrahmen anzuzeigen.

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 dem Jahr und dem Quartal nicht möchten, entfernen Sie ihn einfach.

df['Period'] = df['Year'] + df['Quarter']
11
Samuel Nde

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
10
Pedro M Duarte

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 mal ein 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 __== '__main__':
    main()

wenn sum (concat_df_str2) verwendet wird, ist das Ergebnis nicht einfach concat, es wird in eine Ganzzahl umgewandelt.

9
Colin Wang

Die Verwendung von Zip könnte noch schneller gehen:

df["period"] = [''.join(i) for i in Zip(df["Year"].map(str),df["quarter"])]

Graph:

enter image description here

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()
6
Anton vBR

Diese Lösung verwendet einen Zwischenschritt Komprimieren von zwei Spalten des DataFrame zu einer einzelnen Spalte mit einer Liste der Werte. Dies funktioniert nicht nur für Strings, 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
3
Markus Dutschke

Verwenden Sie .combine_first.

df['Period'] = df['Year'].combine_first(df['Quarter'])
2
Abul

Ich denke, die beste Möglichkeit, 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']
2
Loochie

Wie bereits erwähnt, müssen Sie jede Spalte in eine Zeichenfolge konvertieren und anschließend 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)
2
Ted Petrou

verallgemeinerung auf mehrere Spalten, warum nicht:

columns = ['whatever', 'columns', 'you', 'choose']
df['period'] = df[columns].astype(str).sum(axis=1)
2
geher

Man kann assign Methode von DataFrame verwenden:

df= (pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']}).
  assign(period=lambda x: x.Year+x.quarter ))
1
Sergey

Hier ist meine Zusammenfassung der obigen Lösungen zum Verketten/Kombinieren von zwei Spalten mit int- und str-Wert zu einer neuen Spalte, wobei ein Trennzeichen zwischen den Spaltenwerten verwendet wird. Drei Lösungen arbeiten für diesen Zweck.

# 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)
1
Good Will
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
0
BMW
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)

das Ersetzen von .astype(str) durch .map(str) funktioniert ebenfalls.

0
user8383881