リストを含むpandasセルを、それぞれの値の行に変換することを検討しています。Dataframeセル内のリストを別々の行に分解する方法
ので、これを取る:
を私は相手のインデックス「は、それぞれ値がそれぞれ内の行になるようにnearest_neighbors」列 'に展開した値をスタックしたい場合は、どのように私は最高の?私は認識していないんだ?このついて行くこのような操作のために意図されている方法はありパンダはありますでしょう。
事前のおかげで、みんな。
リストを含むpandasセルを、それぞれの値の行に変換することを検討しています。Dataframeセル内のリストを別々の行に分解する方法
ので、これを取る:
を私は相手のインデックス「は、それぞれ値がそれぞれ内の行になるようにnearest_neighbors」列 'に展開した値をスタックしたい場合は、どのように私は最高の?私は認識していないんだ?このついて行くこのような操作のために意図されている方法はありパンダはありますでしょう。
事前のおかげで、みんな。
以下のコードでは、最初にインデックスをリセットして、行の反復を簡単にしました。
外部リストの各要素がターゲットDataFrameの行で、内部リストの各要素が列の1つであるリストのリストを作成します。このネストされたリストは最終的に連結され、目的のDataFrameを作成します。
Iは関連name
とopponent
とペアnearest_neighbors
の各要素の行を作成するリスト反復とともにlambda
関数を使用します。
最後に、このリストから元の列名を使用してインデックスをname
とopponent
に戻して新しいDataFrameを作成します。
df = (pd.DataFrame({'name': ['A.J. Price'] * 3,
'opponent': ['76ers', 'blazers', 'bobcats'],
'nearest_neighbors': [['Zach LaVine', 'Jeremy Lin', 'Nate Robinson', 'Isaia']] * 3})
.set_index(['name', 'opponent']))
>>> df
nearest_neighbors
name opponent
A.J. Price 76ers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
blazers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
bobcats [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
df.reset_index(inplace=True)
rows = []
_ = df.apply(lambda row: [rows.append([row['name'], row['opponent'], nn])
for nn in row.nearest_neighbors], axis=1)
df_new = pd.DataFrame(rows, columns=df.columns).set_index(['name', 'opponent'])
>>> df_new
nearest_neighbors
name opponent
A.J. Price 76ers Zach LaVine
76ers Jeremy Lin
76ers Nate Robinson
76ers Isaia
blazers Zach LaVine
blazers Jeremy Lin
blazers Nate Robinson
blazers Isaia
bobcats Zach LaVine
bobcats Jeremy Lin
bobcats Nate Robinson
bobcats Isaia
EDIT 2017年6月
次のように別の方法である:適用(pd.Series)と
>>> (pd.melt(df.nearest_neighbors.apply(pd.Series).reset_index(),
id_vars=['name', 'opponent'],
value_name='nearest_neighbors')
.set_index(['name', 'opponent'])
.drop('variable', axis=1)
.dropna()
.sort_index()
)
を私は、これは本当に良い質問だと思いますあなたはハイブを使用するでしょうEXPLODE
では、パンダがデフォルトでこの機能を組み込むべきケースがあると私は思う。あなたはこのようなあなたのリストの列を爆発可能性:
import numpy as np
df = pd.DataFrame({'listcol':[[1,2,3],[4,5,6]]})
X = pd.concat([pd.DataFrame(v, index=np.repeat(k,len(v)))
for k,v in df.listcol.to_dict().items()])
@helpanderrがあなたの元の質問にコメントで示唆されているように、あなたはあなたの元データフレームに、このバックに参加するpd.merge
を使用することができます。
よりよい代替ソリューション:
と同様df = pd.DataFrame({'listcol':[[1,2,3],[4,5,6]]})
# expand df.listcol into its own dataframe
tags = df['listcol'].apply(pd.Series)
# rename each variable is listcol
tags = tags.rename(columns = lambda x : 'listcol_' + str(x))
# join the tags dataframe back to the original dataframe
df = pd.concat([df[:], tags[:]], axis=1)
この列は列を展開しません。 – Oleg
ハイブのEXPLODE機能:
import copy
def pandas_explode(df, column_to_explode):
"""
Similar to Hive's EXPLODE function, take a column with iterable elements, and flatten the iterable to one element
per observation in the output table
:param df: A dataframe to explod
:type df: pandas.DataFrame
:param column_to_explode:
:type column_to_explode: str
:return: An exploded data frame
:rtype: pandas.DataFrame
"""
# Create a list of new observations
new_observations = list()
# Iterate through existing observations
for row in df.to_dict(orient='records'):
# Take out the exploding iterable
explode_values = row[column_to_explode]
del row[column_to_explode]
# Create a new observation for every entry in the exploding iterable & add all of the other columns
for explode_value in explode_values:
# Deep copy existing observation
new_observation = copy.deepcopy(row)
# Add one (newly flattened) value from exploding iterable
new_observation[column_to_explode] = explode_value
# Add to the list of new observations
new_observations.append(new_observation)
# Create a DataFrame
return_df = pandas.DataFrame(new_observations)
# Return
return return_df
これを実行すると、次のエラーが表示されます。 'NameError:グローバル名 'copy'が定義されていません。 – frmsaul
使用apply(pd.Series)
とstack
、その後、reset_index
とto_frame
In [1803]: (df.nearest_neighbors.apply(pd.Series)
.stack()
.reset_index(level=2, drop=True)
.to_frame('nearest_neighbors'))
Out[1803]:
nearest_neighbors
name opponent
A.J. Price 76ers Zach LaVine
76ers Jeremy Lin
76ers Nate Robinson
76ers Isaia
blazers Zach LaVine
blazers Jeremy Lin
blazers Nate Robinson
blazers Isaia
bobcats Zach LaVine
bobcats Jeremy Lin
bobcats Nate Robinson
bobcats Isaia
詳細は
In [1804]: df
Out[1804]:
nearest_neighbors
name opponent
A.J. Price 76ers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
blazers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
bobcats [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
あなたのソリューションのエレガンスが大好きです!万が一、他のアプローチとベンチマークしましたか? – rpyzh
ここでは、より大きなデータフレームのための潜在的な最適化です。これは、「爆発」フィールドに複数の等しい値がある場合、より速く実行されます。 (データフレームが大きいほどフィールド内のユニークな値の数と比較されるほど、このコードが優れています。)
def lateral_explode(dataframe, fieldname):
temp_fieldname = fieldname + '_made_tuple_'
dataframe[temp_fieldname] = dataframe[fieldname].apply(tuple)
list_of_dataframes = []
for values in dataframe[temp_fieldname].unique().tolist():
list_of_dataframes.append(pd.DataFrame({
temp_fieldname: [values] * len(values),
fieldname: list(values),
}))
dataframe = dataframe[list(set(dataframe.columns) - set([fieldname]))]\
.merge(pd.concat(list_of_dataframes), how='left', on=temp_fieldname)
del dataframe[temp_fieldname]
return dataframe
私はこれまで.iloc
でデータフレームを延ばし、をターゲット列を平坦バック割り当てるさ見出さ最速方法。
df = (pd.DataFrame({'name': ['A.J. Price'] * 3,
'opponent': ['76ers', 'blazers', 'bobcats'],
'nearest_neighbors': [['Zach LaVine', 'Jeremy Lin', 'Nate Robinson', 'Isaia']] * 3})
.set_index(['name', 'opponent']))
df = pd.concat([df]*10)
df
Out[3]:
nearest_neighbors
name opponent
A.J. Price 76ers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
blazers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
bobcats [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
76ers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
blazers [Zach LaVine, Jeremy Lin, Nate Robinson, Isaia]
...
を考えると、次の修正候補:
col_target = 'nearest_neighbors'
def extend_iloc():
# Flatten columns of lists
col_flat = [item for sublist in df[col_target] for item in sublist]
# Row numbers to repeat
lens = df[col_target].apply(len)
vals = range(df.shape[0])
ilocations = np.repeat(vals, lens)
# Replicate rows and add flattened column of lists
cols = [c for c in df.columns if c != col_target]
new_df = df.iloc[ilocations, cols].copy()
new_df[col_target] = col_flat
return new_df
def melt():
return (pd.melt(df[col_target].apply(pd.Series).reset_index(),
id_vars=['name', 'opponent'],
value_name=col_target)
.set_index(['name', 'opponent'])
.drop('variable', axis=1)
.dropna()
.sort_index())
def stack_unstack():
return (df[col_target].apply(pd.Series)
.stack()
.reset_index(level=2, drop=True)
.to_frame(col_target))
私はextend_iloc()
が最速であることを見つける:(ビット複製)通常の入力が与えられ
%timeit extend_iloc()
3.11 ms ± 544 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit melt()
22.5 ms ± 1.25 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit stack_unstack()
11.5 ms ± 410 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
すばらしい評価 – javadba
あなたはあなたの希望する出力の例を与えることができますか?あなたはこれまでに試したことがありますか?カット&ペーストすることができるサンプルデータを提供すると、他の人が手助けするのが最も簡単です。 – dagrha
'pd.DataFrame(df.nearest_neighbors.values.tolist())'を使ってこの列を展開し、それを他の列と貼り付ける 'pd.merge'を使うことができます。 – hellpanderrr
@helpanderr 'values.tolist()'はここでは何もしません。列は既にリストになっています – maxymoo