Mam ramkę danych 20 x 4000 w Pythonie, używając pand. Dwie z tych kolumn są nazwane Year
i quarter
. Chciałbym utworzyć zmienną o nazwie period
make Year = 2000
i quarter= q2
into 2000q2
.
Czy ktoś może w tym pomóc?
Mam ramkę danych 20 x 4000 w Pythonie, używając pand. Dwie z tych kolumn są nazwane Year
i quarter
. Chciałbym utworzyć zmienną o nazwie period
make Year = 2000
i quarter= q2
into 2000q2
.
Czy ktoś może w tym pomóc?
Odpowiedzi:
jeśli obie kolumny są łańcuchami, możesz je bezpośrednio łączyć:
df["period"] = df["Year"] + df["quarter"]
Jeśli jedna (lub obie) kolumny nie są napisane ciągiem, należy je najpierw przekonwertować,
df["period"] = df["Year"].astype(str) + df["quarter"]
Jeśli chcesz dołączyć wiele kolumn ciągów, możesz użyć agg
:
df['period'] = df[['Year', 'quarter', ...]].agg('-'.join, axis=1)
Gdzie „-” jest separatorem.
sum
.
dataframe["period"] = dataframe["Year"].map(str) + dataframe["quarter"].map(str)
map, to po prostu stosuje konwersję ciągów do wszystkich wpisów.
df = pd.DataFrame({'Year': ['2014', '2015'], 'quarter': ['q1', 'q2']})
df['period'] = df[['Year', 'quarter']].apply(lambda x: ''.join(x), axis=1)
Uzyskuje tę ramkę danych
Year quarter period
0 2014 q1 2014q1
1 2015 q2 2015q2
Ta metoda uogólnia na dowolną liczbę kolumn łańcuchowych, zastępując df[['Year', 'quarter']]
dowolnym wycinkiem kolumny ramki danych, np df.iloc[:,0:2].apply(lambda x: ''.join(x), axis=1)
.
Możesz sprawdzić więcej informacji na temat metody Apply () tutaj
lambda x: ''.join(x)
jest tylko ''.join
nie?
lambda x: ''.join(x)
konstrukcji lambda nic nie robi; to jak używanie lambda x: sum(x)
zamiast po prostu sum
.
''.join
, tj df['period'] = df[['Year', 'quarter']].apply(''.join, axis=1)
. :
join
przyjmuje tylko str
wystąpienia iterowalne . Użyj a, map
aby przekonwertować je wszystkie, str
a następnie użyj join
.
[''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
lub nieco wolniej, ale bardziej kompaktowo:
df.Year.str.cat(df.quarter)
df['Year'].astype(str) + df['quarter']
AKTUALIZACJA: Wykres czasowy Pandas 0.23.4
Przetestujmy to na 200 000 wierszy 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)
AKTUALIZACJA: nowe czasy przy użyciu Pandas 0.19.0
Czas bez optymalizacji CPU / GPU (posortowane od najszybszego do najwolniejszego):
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
Czas przy użyciu optymalizacji procesora / 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
Odpowiedz wkład od @ anton-vbr
df.T.apply(lambda x: x.str.cat(sep=''))
Sposób cat()
na .str
akcesor działa bardzo dobrze na to:
>>> 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()
pozwala nawet dodać separator, więc na przykład załóżmy, że masz tylko liczby całkowite dla roku i okresu, możesz to zrobić:
>>> 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
Łączenie wielu kolumn to tylko kwestia przekazania listy serii lub ramki danych zawierającej wszystkie oprócz pierwszej kolumny jako parametr do str.cat()
wywołania w pierwszej kolumnie (serii):
>>> 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
Zauważ, że jeśli twoja ramka danych / serii pand ma wartości zerowe, musisz dołączyć parametr na_rep, aby zastąpić wartości NaN ciągiem, w przeciwnym razie połączona kolumna będzie domyślnie ustawiona na NaN.
lambda
lub map
; również czyta to najczystiej.
str.cat()
. Zmienię odpowiedź
sep
słowo kluczowe? w pandach-0.23.4. Dzięki!
sep
parametr jest konieczny tylko wtedy, gdy zamierzasz oddzielić części połączonego łańcucha. Jeśli pojawi się błąd, pokaż nam swój nieudany przykład.
Tym razem użycie funkcji lamba z 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
Pozwala to na pracę z nie-ciągami i formatowanie wartości w razie potrzeby.
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
Prosta odpowiedź na twoje pytanie.
year quarter
0 2000 q1
1 2000 q2
> df['year_quarter'] = df['year'] + '' + df['quarter']
> print(df['year_quarter'])
2000q1
2000q2
Year
nie jest łańcuchem
df['Year'].astype(str) + '' + df['quarter'].astype(str)
Chociaż odpowiedź @silvado jest dobre, jeśli zmieni df.map(str)
się df.astype(str)
to będzie szybciej:
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
Załóżmy swoje dataframe
IS df
z kolumnami Year
i Quarter
.
import pandas as pd
df = pd.DataFrame({'Quarter':'q1 q2 q3 q4'.split(), 'Year':'2000'})
Załóżmy, że chcemy zobaczyć ramkę danych;
df
>>> Quarter Year
0 q1 2000
1 q2 2000
2 q3 2000
3 q4 2000
Na koniec połącz Year
i Quarter
następujące elementy.
df['Period'] = df['Year'] + ' ' + df['Quarter']
Teraz możesz print
df
zobaczyć wynikową ramkę danych.
df
>>> Quarter Year Period
0 q1 2000 2000 q1
1 q2 2000 2000 q2
2 q3 2000 2000 q3
3 q4 2000 2000 q4
Jeśli nie chcesz odstępu między rokiem a kwartałem, po prostu usuń go, wykonując tę czynność;
df['Period'] = df['Year'] + df['Quarter']
df['Period'] = df['Year'].map(str) + df['Quarter'].map(str)
TypeError: Series cannot perform the operation +
kiedy biegnę albo df2['filename'] = df2['job_number'] + '.' + df2['task_number']
albo df2['filename'] = df2['job_number'].map(str) + '.' + df2['task_number'].map(str)
.
df2['filename'] = df2['job_number'].astype(str) + '.' + df2['task_number'].astype(str)
działało.
dataframe
który utworzyłem powyżej, zobaczysz, że wszystkie kolumny są string
s.
Oto implementacja, którą uważam za bardzo wszechstronną:
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
Ponieważ dane są wstawiane do ramki danych, to polecenie powinno rozwiązać problem:
df['period'] = df[['Year', 'quarter']].apply(lambda x: ' '.join(x.astype(str)), axis=1)
bardziej wydajny jest
def concat_df_str1(df):
""" run time: 1.3416s """
return pd.Series([''.join(row.astype(str)) for row in df.values], index=df.index)
a oto próba czasowa:
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()
końcowy, gdy sum
użyje się (concat_df_str2), wynik nie jest po prostu concat, przejdzie do liczby całkowitej.
df.values[:, 0:3]
Lub df.values[:, [0,2]]
.
uogólniając na wiele kolumn, dlaczego nie:
columns = ['whatever', 'columns', 'you', 'choose']
df['period'] = df[columns].astype(str).sum(axis=1)
Korzystanie zip
może być jeszcze szybsze:
df["period"] = [''.join(i) for i in zip(df["Year"].map(str),df["quarter"])]
Wykres:
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()
Najprostsze rozwiązanie:
Ogólne rozwiązanie
df['combined_col'] = df[['col1', 'col2']].astype(str).apply('-'.join, axis=1)
Pytanie specyficzne rozwiązanie
df['quarter_year'] = df[['quarter', 'year']].astype(str).apply(''.join, axis=1)
Określ preferowany separator w cudzysłowie przed .join
W tym rozwiązaniu zastosowano etap pośredni kompresujący dwie kolumny DataFrame do pojedynczej kolumny zawierającej listę wartości. Działa to nie tylko dla ciągów, ale dla wszystkich rodzajów typów kolumn
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)
Wynik:
Year quarter list period
0 2014 q1 [2014, q1] 2014q1
1 2015 q2 [2015, q2] 2015q2
Jak wielu wspomniało wcześniej, należy przekonwertować każdą kolumnę na ciąg, a następnie użyć operatora plus, aby połączyć dwie kolumny ciągów. Możesz uzyskać dużą poprawę wydajności, używając 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')
. Zarówno numer_zadania, jak i numer_zadania są liczbami całkowitymi.
df['Year'].values.astype(str) + df.quarter
Myślę, że najlepszym sposobem na połączenie kolumn w pandy jest konwersja obu kolumn na liczby całkowite, a następnie na str.
df[['Year', 'quarter']] = df[['Year', 'quarter']].astype(int).astype(str)
df['Period']= df['Year'] + 'q' + df['quarter']
Oto moje podsumowanie powyższych rozwiązań, aby połączyć / połączyć dwie kolumny z wartościami int i str w nową kolumnę, używając separatora między wartościami kolumn. W tym celu działają trzy rozwiązania.
# 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)
Zastosowanie .combine_first
.
df['Period'] = df['Year'].combine_first(df['Quarter'])
.combine_first
spowoduje 'Year'
zapisanie wartości w 'Period'
, lub, jeśli jest Null, wartość z 'Quarter'
. Nie połączy dwóch łańcuchów i nie zapisze ich w '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)
Na przykład:
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"])
lub jeśli wartości są takie jak [2000] [4] i chcesz zrobić [2000q4]
dataframe["period"] = dataframe["Year"].astype(str).add('q').add(dataframe["quarter"]).astype(str)
podstawiając .astype(str)
z .map(str)
prac zbyt.
add(dataframe.iloc[:, 0:10])
na przykład?