Dataframe 셀 내부의 목록을 별도의 행으로 분해하는 방법
목록이 포함 된 팬더 셀을 각 값에 대한 행으로 바꾸려고합니다.
그래서 이것을 가져 가십시오.
nearest_neighbors각 값이 각 opponent인덱스 내의 행이되도록 열의 값을 압축 해제하고 쌓으려면 어떻게하면 좋을까요? 이와 같은 작업을위한 pandas 메서드가 있습니까?
아래 코드에서 먼저 인덱스를 재설정하여 행 반복을 더 쉽게 만듭니다.
외부 목록의 각 요소가 대상 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)하고 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]
나는 이것이 정말 좋은 질문이라고 생각합니다. 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)
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
pandas 0.25 에서는 다음과 같은 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
따라서이 모든 답변은 훌륭하지만 ^ 정말 간단한 ^ 무언가를 원했기 때문에 여기에 내 기여가 있습니다.
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
이것은 각 목록 열의 목록 길이가 같다고 가정합니다.
'Program Club' 카테고리의 다른 글
| 노드에서 모든 자식 요소를 제거한 다음 다른 색상과 크기로 다시 적용하려면 어떻게해야합니까? (0) | 2020.10.16 |
|---|---|
| 이 C ++ 프로그램이 그렇게 빠른 이유는 무엇입니까? (0) | 2020.10.16 |
| 어떤 TensorFlow 및 CUDA 버전 조합이 호환 되나요? (0) | 2020.10.16 |
| yywrap에 대한 정의되지 않은 참조 (0) | 2020.10.16 |
| 키 값 관찰을 수행하고 UIView의 프레임에서 KVO 콜백을 받으려면 어떻게해야합니까? (0) | 2020.10.16 |
