我有了一个看起来像一列数据框:
Japan
valA
valB
Ghana
valC
valD
...
我想从这个名单中提取的国名,把它们变成像这样的另一列:
Japan valA
Japan valB
Ghana valC
Ghana valD
我相信有这个答案已经上如此,但我一直没能找到正确的关键字把它。
现在,我做以下,但后来我不得不放弃最初包含的国名行:
def get_country(row):
if #decide if it's a country name:
return row[0]
df['country'] = df.apply(get_country, axis=1).fillna(method='ffill')
清理数据时,这似乎是一个相当常见的情况是有这样做的一个标准的/更好的办法?
我可以让你开始使用map
和ffill
。
def is_country(x):
# TODO - fill in the logic for this stub.
return x in {'Japan', 'Ghana'}
df
A
0 Japan
1 valA
2 valB
3 Ghana
4 valC
5 valD
df.assign(B=df['A'].where(df['A'].map(is_country)).ffill()).query('A != B')
A B
1 valA Japan
2 valB Japan
4 valC Ghana
5 valD Ghana
您可以使用包像pycountry
(或类似的东西),以验证国名。
import pycountry
countries = {x.name for x in pycountry.countries} # Initialise a set.
def is_country(x):
return x in countries
虽然这个定义,可以简化您的代码,
df.assign(B=df['A'].where(df['A'].isin(countries)).ffill()).query('A != B')
而摆脱is_country
功能的全部。
使用提取物
new_df = df['col'].str.extract('(val.*)?(.*)').replace('', np.nan).rename(columns = {1:'Country', 0:'Value'})
new_df['Country'] = new_df['Country'].ffill()
new_df.dropna(inplace = True)
Value Country
1 valA Japan
2 valB Japan
4 valC Ghana
5 valD Ghana
下面是使用groupby
+ pd.concat
的一种方式。你可以明确地定义countries
或使用自己喜欢的来源。
df = pd.DataFrame({'col': ['Japan', 'valA', 'valB', 'Ghana', 'valC', 'valD']})
countries = ['Japan', 'Ghana']
grouper = df['col'].groupby(df['col'].isin(countries).cumsum())
dfs = (pd.DataFrame({'Country': df_ctry.iat[0], 'Value': df_ctry.iloc[1:]}) \
for _, df_ctry in grouper)
res = pd.concat(dfs, ignore_index=True)
print(res)
Country Value
0 Japan valA
1 Japan valB
2 Ghana valC
3 Ghana valD