Selecting only non-empty cells in a row Using Pandas to read a 14k lines CSV with many empty cells - what I call "Emmenthaler data", lots of holes :-) . A very short, simplified sampler (urlbuilder.csv): 

"one","two","three"
"","foo","bacon",""
"spam","bar",""


The cells contain information to match against this web API, like this: 

http://base_URL&amp;two="foo"&amp;three="bacon"
http://base_URL&amp;one="spam"&amp;two="bar"


Leaving values empty in the URL (``...one=""&amp;two="bar"`) would give wrong results. So I want to use just the non-empty fields in each row. To illustrate the method:

import pandas as pd


def buildurl(row, colnames):
    URL = 'http://someAPI/q?'
    values = row.one, row.two, row.three  # ..ugly.. 

    for value,field in zip(values, colnames):
        if not pd.isnull(value): 
            URL = '{}{}:{}&amp;'.format(URL, field, value)

    return URL


df = pd.read_csv('urlbuilder.csv', encoding='utf-8-sig', engine='python')
colnames = list(df.columns)

for row in df.itertuples():
    url = buildurl(row, colnames)
    print(url)


It works and it's probably better than a cascade of if not isnull's. But I still have this loud hunch that there are much more elegant ways of doing this. Yet I can't seem to find them, probably I'm not googling for the right jargon. 

Please comment
For anything related to building URL query strings from key-values pairs, you should let urllib.parse.urlencode do the work for you. It can also handle quoting and other special cases for you. To do that, you have to convert your data to a dictionary.

This is easy if you start with a pd.Series:

from urllib.parse import urlencode


def build_url_params(serie):
    parameters = serie[~pd.isnull(serie)].to_dict()
    return urlencode(parameters)


Then you just need to provide Series to this function instead of tuples:

def populate_url_params(df):
    df['URL parameters'] = df.apply(build_url_params, axis=1)


if __name__ == '__main__':
    df = pd.read_csv('urlbuilder.csv', encoding='utf-8-sig', engine='python')
    populate_url_params(df)
    print(df)


Or if you want to go the manual iteration route, you can use df.iterrows() instead of df.itertuples().