목록이 포함 된 팬더 셀을 각 값에 대한 행으로 바꾸려고합니다.
그래서 이것을 가져 가십시오.
nearest_neighbors
각 값이 각 opponent
인덱스 내의 행이되도록 열의 값을 압축 해제하고 스택하려면 어떻게하면 좋을까요? 이와 같은 작업을위한 pandas 메서드가 있습니까?
pd.DataFrame(df.nearest_neighbors.values.tolist())
이 열의 포장을 풀고 다른 열과 pd.merge
붙일 때 사용할 수 있습니다 .
values.tolist()
여기서 아무것도 하지 않는다고 생각한다 ; 열은 이미 목록입니다
답변:
아래 코드에서 먼저 인덱스를 재설정하여 행 반복을 더 쉽게 만듭니다.
외부 목록의 각 요소가 대상 DataFrame의 행이고 내부 목록의 각 요소가 열 중 하나 인 목록 목록을 만듭니다. 이 중첩 된 목록은 궁극적으로 연결되어 원하는 DataFrame을 생성합니다.
내가 사용 lambda
의 각 요소에 대해 행을 만들 목록 반복과 기능을 함께를 nearest_neighbors
관련과 짝 name
하고 opponent
.
마지막으로, 나는이 목록에서 새 DataFrame (원래 열 이름을 사용하여 인덱스 다시 설정 생성 name
과 opponent
).
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
2017 년 6 월 수정
다른 방법은 다음과 같습니다.
>>> (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()
)
apply(pd.Series)
가장 작은 프레임에서는 괜찮지 만 합리적인 크기의 프레임에 대해서는 더 성능이 좋은 솔루션을 재고해야합니다. 코드에서 pandas apply ()를 언제 사용해야합니까?를 참조하십시오 . (더 나은 해결책은 열을 먼저 나열하는 것입니다.)
explode()
메서드를 추가 하여 목록과 같은 열을 분해하는 작업이 크게 단순화 되었습니다 . 여기와 동일한 df 설정을 사용하여 예제와 함께 답변 을 추가 했습니다 .
사용 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]
df.nearest_neighbors.apply(pd.Series)
나에게 매우 놀랍습니다.
explode()
메서드를 추가
하여 목록과 같은 열을 분해하는 작업이 크게 단순화 되었습니다 .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.explode('nearest_neighbors')
밖:
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
나는 이것이 정말 좋은 질문이라고 생각합니다. Hive에서는를 사용할 것 EXPLODE
입니다. Pandas가 기본적으로이 기능을 포함해야하는 경우가 있다고 생각합니다. 아마도 다음과 같이 중첩 된 생성기 이해로 목록 열을 폭발시킬 것입니다.
pd.DataFrame({
"name": i[0],
"opponent": i[1],
"nearest_neighbor": neighbour
}
for i, row in df.iterrows() for neighbour in row.nearest_neighbors
).set_index(["name", "opponent"])
빠른 I 발견 방법은 지금까지와 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 = [i for i,c in enumerate(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)
cols = [c for c in df.columns if c != col_target]
해야한다 : 오류를 열 인덱스가 표시되지 않은 경우. cols = [i for i,c in enumerate(df.columns) if c != col_target]
df.iloc[ilocations, cols].copy()
apply (pd.Series)로 더 좋은 대안 솔루션 :
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)
Hive의 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: global name 'copy' is not defined
따라서이 모든 답변은 훌륭하지만 ^ 정말 간단한 ^ 무언가를 원했기 때문에 여기에 내 기여가 있습니다.
def explode(series):
return pd.Series([x for _list in series for x in _list])
그게 다야 .. 목록이 '폭발'되는 새 시리즈를 원할 때 이것을 사용하십시오. 다음은 타코 선택에 대해 value_counts ()를 수행하는 예입니다. :)
In [1]: my_df = pd.DataFrame(pd.Series([['a','b','c'],['b','c'],['c']]), columns=['tacos'])
In [2]: my_df.head()
Out[2]:
tacos
0 [a, b, c]
1 [b, c]
2 [c]
In [3]: explode(my_df['tacos']).value_counts()
Out[3]:
c 3
b 2
a 1
다음은 더 큰 데이터 프레임에 대한 잠재적 인 최적화입니다. "exploding"필드에 동일한 값이 여러 개있을 때 더 빨리 실행됩니다. (데이터 프레임이 필드의 고유 값 수에 비해 클수록이 코드의 성능이 향상됩니다.)
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
모든 목록 열을 자동으로 평면화하도록 Oleg의 대답을 확장합니다 .
def extend_iloc(df):
cols_to_flatten = [colname for colname in df.columns if
isinstance(df.iloc[0][colname], list)]
# Row numbers to repeat
lens = df[cols_to_flatten[0]].apply(len)
vals = range(df.shape[0])
ilocations = np.repeat(vals, lens)
# Replicate rows and add flattened column of lists
with_idxs = [(i, c) for (i, c) in enumerate(df.columns) if c not in cols_to_flatten]
col_idxs = list(zip(*with_idxs)[0])
new_df = df.iloc[ilocations, col_idxs].copy()
# Flatten columns of lists
for col_target in cols_to_flatten:
col_flat = [item for sublist in df[col_target] for item in sublist]
new_df[col_target] = col_flat
return new_df
이것은 각 목록 열의 목록 길이가 같다고 가정합니다.
apply (pd.Series)를 사용하는 대신 열을 평평하게 할 수 있습니다. 이것은 성능을 향상시킵니다.
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']))
%timeit (pd.DataFrame(df['nearest_neighbors'].values.tolist(), index = df.index)
.stack()
.reset_index(level = 2, drop=True).to_frame('nearest_neighbors'))
1.87 ms ± 9.74 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit (df.nearest_neighbors.apply(pd.Series)
.stack()
.reset_index(level=2, drop=True)
.to_frame('nearest_neighbors'))
2.73 ms ± 16.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)